from opcua import Client
import pymssql
from datetime import datetime, timedelta
import time as times
# from time import time  # 在文件顶部导入
import sys
import ctypes
from PySide6.QtGui import QPen, QColor, QVector3D, QPainter
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QSizePolicy, QTableWidgetItem, QDialog, \
    QFileDialog, QVBoxLayout
from PySide6.QtCore import QThread, QDateTime, QTimer, QPoint, QPointF, Qt, QMargins, QObject, Signal, Slot
from PySide6.QtCharts import QChart, QLineSeries, QDateTimeAxis, QValueAxis, QChartView
from PySide6.QtDataVisualization import QAbstract3DGraph, QAbstract3DSeries, QScatter3DSeries, QScatterDataItem
from PySide6.QtOpenGLWidgets import QOpenGLWidget

from reportlab.lib import colors, fonts
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle
from reportlab.lib.pagesizes import A1, A3
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

from random import uniform  # 随机数函数
from openpyxl import Workbook  # excel导出文件
from openpyxl.styles import Alignment
import numpy as np  # 存储和处理大型矩阵阵列数组
import json  # json数组文件的读写库
from hashlib import sha256  # 用于哈希加密的驱动库
import os
from collections import defaultdict  # 动态生成字典

from Auxiliary_interface.jiemian import Ui_MainWindow  # 调用UI文件，并编写逻辑,  主界面
from Auxiliary_interface.denglu import Ui_Dialog  # 登录界面UI文件，并编写逻辑
from Auxiliary_interface.UI_SHENGCHAN import Ui_shengchan  # 生产数据输入界面UI文件，并编写逻辑
from Auxiliary_interface.Historical_images import MainWindow  # 历史图像界面UI文件，并编写逻辑
from Auxiliary_interface import chartview  # 二维图像（实时与历史）渲染显示对象
from Auxiliary_interface.customscatter import CustomScatter  # （实时）3D界面对象
from Auxiliary_interface.Gun_c_p import gun_c_p  # 枪坐标与参数数据存储文件

from dbutils.pooled_db import PooledDB     # sql操作池库
import threading                           # 阻塞等待库

# 提前注册字体（建议在程序初始化时执行）
def register_chinese_font():
    # 注册中文字体（需要实际字体文件路径）
    font_path = "drive/STZHONGS.TTF"  # 这里使用思源黑体

    # 如果字体文件不在当前目录，需要提供绝对路径
    # font_path = r"C:\Fonts\SourceHanSansSC-Regular.ttf"

    if os.path.exists(font_path):
        pdfmetrics.registerFont(TTFont(name="ChineseFont",
                                       filename=font_path))  # 附加修复字符映射
        fonts.addMapping("ChineseFont", 0, 0, "ChineseFont")  # 正常字体
        print("中文字体注册成功")
    else:
        raise FileNotFoundError(f"字体文件未找到: {font_path}")

# 在程序初始化时调用
register_chinese_font()

window1 = None  # 登录窗口对象
window2 = None  # 生产数据窗口对象
window3 = None  # 生产数据窗口对象
window4 = None  # 3D焊接过程显示窗口对象

username_main = None  # 登录账号名称
permissions_main = None  # 当前权限记录

# 周期时间初始化
cycle_1 = 1000

# opcua链接信息
url = "opc.tcp://192.168.250.10:4840"
opc_username = "admin"
opc_password = "88888888"
To_be_allocated_name = ""  # 历史待分配数据
# 发那科库调入并绑定
focas = ctypes.cdll.LoadLibrary("drive/Fwlib64.dll")
focas.cnc_allclibhndl3.restype = ctypes.c_short

# CNC系统连接并读取值----A枪
ipA = "192.168.250.20"
portA = 8193
timeout = 10
libhA = ctypes.c_ushort(0)  # CNC数据读取注册对象

# 赋值----B枪
ipB = "192.168.250.30"
portB = 8193
libhB = ctypes.c_ushort(0)  # CNC数据读取注册对象

class ODBAXIS(ctypes.Structure):  # 发那科CNC绝对坐标值获取集合
    _fields_ = [("dummy", ctypes.c_short),
                ("type", ctypes.c_short),
                ("data", ctypes.c_long * 5)]  # 读取值存放处

class ODBACT(ctypes.Structure):  # 实际进给率（速度）发那科CNC获取集合
    _fields_ = [("dummy", ctypes.c_short * 2),  # dummy
                ("data", ctypes.c_long * 5)]  # the actual feed rate(F)

servermy = 'DESKTOP-3BQ74EF'  # 数据库服务器名称全局变量
portmy = '1433'  # 数据库端口全局变量
usermy = 'sa'  # 数据库账号全局变量
passwordmy = '666888xxx'  # 数据库密码全局变量
databasemy = 'testDB'  # 数据库库名全局变量
newdatabasemy = 'testDB'  # 数据库新建库名全局变量

# cursor = None  # 数据库注册全局变量
# conn = None  # 数据库登录全局变量
client = None  # opcua登录全局变量

results0_1 = []  # 查询历史数据时的时间属性，X轴
results1_1 = []  # 查询历史数据时的数据传递至图像界面的中间容器

# 临时同时坐标变量
# 三个递增的矩形，在Z高度上递增，矩形长*宽=2500*6000，每次有1mm的偏差量---------起点X：2650，Y：8850，Z：980，层间距：800+-5
Do_c = False  # 关门变量
CH_zh = False  # 抽真空
HAN_j_A = False  # A枪焊接
HAN_j_B = False  # B枪焊接

yd_jieduan_A = 0  # A枪运动步骤
yd_jieduan_B = 0  # B枪运动步骤

def is_connected(client):
    return client._uasocket and not client._uasocket.is_closing()

# -------------------3D绕Z轴旋转算法--------------------
def batch_rotate_around_y(points, center, angle_degrees):
    """
    批量绕同一中心Y轴旋转
        :param points: N×4数组，原始点集
        :param center: 1×3数组，公共旋转中心
        :param angle_degrees: 旋转角度（度）
        :return: N×3数组，旋转后坐标
    """
    theta = np.radians(angle_degrees)
    c, s = np.cos(theta), np.sin(theta)

    # 平移至原点（处理X和Z坐标）
    translated = points[:, [1, 3]] - center[[0, 2]]  # 取X、Z列

    # 批量旋转（绕Y轴的旋转矩阵）
    rotated = np.dot(translated, [[c, -s], [s, c]])

    # 反向平移并保持Y轴不变
    return np.column_stack((
        points[:, 0],
        rotated[:, 0] + center[0],  # 新X坐标
        points[:, 2],  # 保持原始Y坐标
        rotated[:, 1] + center[2]  # 新Z坐标
    ))

# ----------------------添加曲线-----------------------
def quxianluru(np_dates, points, line_chart, axis_x, axis_y, color, pen_style):
    # 录入数据函数：
    #      names：此数据的名称
    #      np_dates：X轴原始数据
    #      points：Y轴原始数据
    #      line_chart：chart对象容器
    #      axis_x：日期X轴对象
    #      axis_y：对应Y轴插入对象
    # print(line_chart)
    chart_line = QLineSeries()
    # 设置曲线的颜色和宽度
    green = QPen(color)
    green.setStyle(Qt.SolidLine)
    green.setWidth(1)
    chart_line.setPen(green)
    line_chart.addSeries(chart_line)
    # print(np_dates[0].date().toString("yyyy-MM-dd")+"到"+np_dates[-1].date().toString("yyyy-MM-dd"))
    line_chart.addAxis(axis_x, Qt.AlignBottom)  # 设置 x 轴的位置
    chart_line.attachAxis(axis_x)               # 将系列与坐标轴关联
    line_chart.addAxis(axis_y, Qt.AlignLeft)    # 设置 y 轴的位置
    chart_line.attachAxis(axis_y)               # 将系列与坐标轴关联

    shuju_zidian = {}
    old_time = np_dates[0]
    # line_chart.addSeries(series)
    # 将 np_dates 转换为 QPointF 对象并添加到系列

    for i in range(len(np_dates)):
        # 将 QDateTime 转换为时间戳并创建 QPointF 对象
        timestamp = np_dates[i].toMSecsSinceEpoch()
        # 然后再进行赋值
        shuju_zidian[timestamp] = points[i]  # 将数据存入字典中，以便在云框显示中获取
        # print(data_x.secsTo(self.old_time))
        if abs(np_dates[i].secsTo(old_time)) > 3:
            if pen_style:
                chart_line = server(line_chart, axis_x, axis_y, color,
                                    Qt.DotLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                pen_style = 0
        else:
            if not pen_style:
                chart_line = server(line_chart, axis_x, axis_y, color,
                                    Qt.SolidLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                pen_style = 1
        old_time = np_dates[i]  # 上一次时间存储
        chart_line.append(QPointF(timestamp, points[i]))  # 使用 QPointF 来表示 (时间戳, 数据点)

    return shuju_zidian, chart_line, pen_style

# ------------------------更新曲线为黑色虚线-----------------------
def server(line_chart, _axisX, _axisY, color, pen_style):  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
    # 设置曲线的颜色和宽度
    # print("real server run")
    green = QPen(color)
    green.setStyle(pen_style)
    green.setWidth(1)
    _series = QLineSeries()
    _series.setPen(green)
    line_chart.addSeries(_series)
    line_chart.legend().markers(_series)[0].setVisible(False)  # 隐藏第二条曲线的图例
    _series.attachAxis(_axisX)
    _series.attachAxis(_axisY)
    return _series

# ----------------多线程逻辑-----------------
    #     # 步骤一：读取PLC内容
    #     # 步骤二：读取A枪数控设备内容
    #     # 步骤三：读取B枪数控设备内容
    #     # 步骤四：判断设备状态：在线状态、枪位置、转台位置、设备报警状况。
class TimerWorker(QObject):
    # 输出信号
    timeout_signal = Signal(object)        # A 移动信息 标签输出
    timeout_signal_B = Signal(object)      # B 移动信息 标签输出
    timeout_duqu_sql = Signal(object)      # A 实时图像更新，数据传输
    timeout_duqu_sql_B = Signal(object)    # B 实时图像更新，数据传输
    t_xyz_rd_A = Signal(object)            # 3D a 输出旋转过后的坐标数据
    t_xyz_rd_B = Signal(object)            # 3D b 输出旋转过后的坐标数据

    # 输入信号
    time_start_A = Signal(str, str, str, str, str, str, int)  # A坐标变化开始信号
    time_start_B = Signal(str, str, str, str, str, str, int)  # B坐标变化开始信号
    time_start1_A = Signal(int)                                      # Asql存储开始信号
    time_start1_B = Signal(int)                                      # Bsql存储开始信号
    time_start2_A = Signal(int, object)                       # A数据处理开始信号
    time_start2_B = Signal(int, object)                       # B数据处理开始信号
    time_start_zht = Signal(int, int, int, int, int)          # 转台数据处理开始信号
    time_start3 = Signal(int, object)                         # plc与逻辑运算
    time_stop1_A = Signal()                                          # Asql存储停止信号
    time_stop1_B = Signal()                                          # Bsql存储停止信号
    old_A = Signal(object)                                           # A旧时间更新
    old_B = Signal(object)                                           # B旧时间更新
    t_xyz_A = Signal(object)                                         # A输入更新的坐标信息（np（日期，X,Y,Z））
    t_xyz_B = Signal(object)                                         # B输入更新的坐标信息（np（日期，X,Y,Z））
    D_Range_IN = Signal(int)                                         # 更新 显示范围 方式
    S_scope_IN = Signal(int)                                         # 更新 保存数据范围 方式

    def __init__(self):
        super().__init__()
        global servermy, portmy, usermy, passwordmy, databasemy
        # 创建数据库连接池（在程序启动时初始化）
        self.connection_pool = PooledDB(
            creator=pymssql,
            mincached=2,  # 初始空闲连接
            maxcached=5,  # 最大空闲连接
            maxconnections=20,  # 最大活动连接
            server=servermy,
            port=portmy,
            user=usermy,
            password=passwordmy,
            database=databasemy,
            charset='utf8',
            autocommit=True  # 保持原有自动提交特性
        )
        self.event1 = threading.Event()    # 阻塞等待对象
        self.old_time_A = None     # 上一次绘制时间，用来判断绘制曲线的长度
        self.re_A = None    # 临时坐标UI输入
        self.re2_A = None
        self.re3_A = None
        self.re4_A = None
        self.x_A = None
        self.y_A = None

        self.old_time_B = None      # 上一次绘制时间，用来判断绘制曲线的长度
        self.re_B = None     # 临时坐标UI输入
        self.re2_B = None
        self.re3_B = None
        self.re4_B = None
        self.x_B = None
        self.y_B = None

        self.start1_a = 0
        self.start1_b = 0

        self.yd_jieduan_A = 9
        self.yd_jieduan_B = 9

        self.shuju_weizhi_A = [None] * 6
        self.shuju_weizhi_A[5] = 0
        self.shuju_weizhi_B = [None] * 6
        self.shuju_weizhi_B[5] = 0

        self.a_r_x = 0           # 旋转中心点坐标
        self.a_r_y = 0
        self.b_r_x = 0
        self.b_r_y = 0

        self.Display_Range = 0      # 显示数据范围    0：仅下束     1：全部
        self.Save_scope = 0         # 保存数据范围    0：仅焊接     1：所有下束    2：全部数据

        self.time_xyz_A = 0      # 时间坐标信息 np数组 A
        self.time_xyz_B = 0      # 时间坐标信息 np数组 B

        # 发送数据处理线程数据库连接成功

        # A枪与B枪参数对象
        self.Gun_p_A = gun_c_p()  # A枪参数
        self.Gun_p_A.Y_l = 8000
        self.Gun_p_B = gun_c_p()  # B枪参数
        self.Gun_p_B.Y_l = 10000

        # 定时器任务定义
        self.timer = QTimer(self)     # A枪运动坐标变化
        self.timer_B = QTimer(self)   # B枪运动坐标变化
        self.timer1 = QTimer(self)    # A枪下束时数据记录入数据库
        self.timer2_A = QTimer(self)  # A实时数据更新图表
        self.timer2_B = QTimer(self)  # B实时数据更新图表
        self.timer3 = QTimer(self)    # 定期读取设备信息

        self.timer.timeout.connect(self.showtime)
        self.timer_B.timeout.connect(self.showtime_B)
        self.timer1.timeout.connect(self.showtime1)
        self.timer2_A.timeout.connect(self.showtime2_A)
        self.timer2_B.timeout.connect(self.showtime2_B)
        self.timer3.timeout.connect(self.showtime3)

        self.timer.start(1000)         # 开始定时发送坐标数据 A
        self.timer_B.start(1000)       # 开始定时发送坐标数据 B

        self.time_start_A.connect(self.start_timer)        # A枪运动坐标变化、自动跨线程连接
        self.time_start_B.connect(self.start_timer_B)      # B枪运动坐标变化、自动跨线程连接
        self.time_start1_A.connect(self.start_timer1)      # A枪下束时数据记录入数据库、自动跨线程连接
        self.time_start1_B.connect(self.start_timer1_B)    # B枪下束时数据记录入数据库、自动跨线程连接
        self.time_start2_A.connect(self.start_timer2_A)    # A实时数据处理、自动跨线程连接
        self.time_start2_B.connect(self.start_timer2_B)    # B实时数据处理、自动跨线程连接
        self.time_start_zht.connect(self.start_timer_zht)  # B实时数据处理、自动跨线程连接
        self.time_stop1_A.connect(self.stop_timer1)        # A停止记录
        self.time_stop1_B.connect(self.stop_timer1_B)      # B停止记录
        self.old_A.connect(self.re_old_a)                  # A旧时间更新
        self.old_B.connect(self.re_old_b)                  # B旧时间更新
        self.t_xyz_A.connect(self.t_xyz_a)                 # A输入更新的坐标信息（np（日期，X,Y,Z））
        self.t_xyz_B.connect(self.t_xyz_b)                 # B输入更新的坐标信息（np（日期，X,Y,Z））
        self.D_Range_IN.connect(self.D_Range_in)                 # B输入更新的坐标信息（np（日期，X,Y,Z））
        self.S_scope_IN.connect(self.S_scope_in)                 # B输入更新的坐标信息（np（日期，X,Y,Z））

    @Slot(str, str, str, str, str, str, int)
    def start_timer(self, re_A, re2_A, re3_A, re4_A, x_A, y_A, jieduan_A):  # A枪运动坐标变化
        try:
            self.re_A = re_A
            self.re2_A = re2_A
            self.re3_A = re3_A
            self.re4_A = re4_A
            self.y_A = y_A
            self.x_A = x_A
            self.yd_jieduan_A = jieduan_A
            # self.timer.start(interval)
        except Exception as e:
            print(f"Error starting timer: {e}")

    @Slot(str, str, str, str, str, str, int)
    def start_timer_B(self, re_B, re2_B, re3_B, re4_B, x_B, y_B, jieduan_B):  # B枪运动坐标变化
        self.re_B = re_B
        self.re2_B = re2_B
        self.re3_B = re3_B
        self.re4_B = re4_B
        self.x_B = x_B
        self.y_B = y_B
        self.yd_jieduan_B = jieduan_B
        # self.timer_B.start(interval)

    @Slot(int)
    def start_timer1(self, interval):  # A枪下束记录任务
        self.start1_a = 1
        if not self.timer1.isActive():
            self.timer1.start(interval)

    @Slot(int)
    def start_timer1_B(self, interval):  # B枪下束记录任务
        self.start1_b = 1
        if  not self.timer1.isActive():
            self.timer1.start(interval)

    @Slot(int, object)
    def start_timer2_A(self, interval, old_time):  # A实时数据更新处理
        self.old_time_A = old_time
        self.timer2_A.start(interval)

    @Slot(int, object)
    def start_timer2_B(self, interval, old_time):  # A实时数据更新处理
        self.old_time_B = old_time
        self.timer2_B.start(interval)

    @Slot(int, int, int, int, int)
    def start_timer_zht(self, interval, a_r_x, a_r_y, b_r_x, b_r_y):  # A实时数据更新处理
        self.timer3.start(interval)
        self.a_r_x = a_r_x
        self.a_r_y = a_r_y
        self.b_r_x = b_r_x
        self.b_r_y = b_r_y
    # def stop_timer(self):
    #     self.timer.stop()

    @Slot(object)
    def t_xyz_a(self, xyz_a):
        self.time_xyz_A = xyz_a

    @Slot(object)
    def t_xyz_b(self, xyz_b):
        self.time_xyz_B = xyz_b

    @Slot(int)
    def D_Range_in(self, in1):
        self.Display_Range = in1

    @Slot(int)
    def S_scope_in(self, in1):
        self.Save_scope = in1

    @Slot(object)
    def re_old_a(self, old):
        self.old_time_A = old

    @Slot(object)
    def re_old_b(self, old):
        self.old_time_B = old

    @Slot()
    def stop_timer1(self):
        self.start1_a = 0
        if not(self.start1_b or self.start1_a):
            self.timer1.stop()

    @Slot()
    def stop_timer1_B(self):
        self.start1_b = 0
        if not(self.start1_b or self.start1_a):
            self.timer1.stop()

    # @Slot()
    # def change_xyz(self):
        # self.timer1_B.stop()

    # ---------------------定时器任务-------------------
    def showtime(self):  # A枪坐标移动任务
        # print("time_show")
        global Do_c
        global CH_zh

        if self.yd_jieduan_A == 0:
            self.yd_jieduan_A = 1

        if self.yd_jieduan_A == 1 and self.Gun_p_A.X_l < self.Gun_p_A.mb_X_l:
            self.Gun_p_A.X_l = self.Gun_p_A.X_l + 10
        elif self.yd_jieduan_A == 1 and self.Gun_p_A.X_l > self.Gun_p_A.mb_X_l:
            self.Gun_p_A.X_l = self.Gun_p_A.X_l - 10
        elif self.yd_jieduan_A == 1 and self.Gun_p_A.X_l == self.Gun_p_A.mb_X_l:
            self.yd_jieduan_A = 2

        if self.yd_jieduan_A == 2:
            self.Gun_p_A.R_l = self.Gun_p_A.R_l + float(self.re_A)
            if self.Gun_p_A.R_l > 360:
                self.Gun_p_A.R_l = self.Gun_p_A.R_l - 360
            self.yd_jieduan_A = 3

        if self.yd_jieduan_A == 3 and self.Gun_p_A.Y_l < self.Gun_p_A.mb_Y_l:
            self.Gun_p_A.Y_l = self.Gun_p_A.Y_l + 10
        elif self.yd_jieduan_A == 3 and self.Gun_p_A.Y_l > self.Gun_p_A.mb_Y_l:
            self.Gun_p_A.Y_l = self.Gun_p_A.Y_l - 10
        elif self.yd_jieduan_A == 3 and self.Gun_p_A.Y_l == self.Gun_p_A.mb_Y_l:
            self.yd_jieduan_A = 4

        if self.yd_jieduan_A == 4:
            self.Gun_p_A.R_l = self.Gun_p_A.R_l + float(self.re2_A)
            if self.Gun_p_A.R_l > 360:
                self.Gun_p_A.R_l = self.Gun_p_A.R_l - 360
            self.yd_jieduan_A = 5

        if self.yd_jieduan_A == 5 and self.Gun_p_A.X_l < self.Gun_p_A.mb_X_l + int(self.x_A):
            self.Gun_p_A.X_l = self.Gun_p_A.X_l + 10
        elif self.yd_jieduan_A == 5 and self.Gun_p_A.X_l > self.Gun_p_A.mb_X_l + int(self.x_A):
            self.Gun_p_A.X_l = self.Gun_p_A.X_l - 10
        elif self.yd_jieduan_A == 5 and self.Gun_p_A.X_l == self.Gun_p_A.mb_X_l + int(self.x_A):
            self.yd_jieduan_A = 6

        if self.yd_jieduan_A == 6:
            self.Gun_p_A.R_l = self.Gun_p_A.R_l + float(self.re3_A)
            if self.Gun_p_A.R_l > 360:
                self.Gun_p_A.R_l = self.Gun_p_A.R_l - 360
            self.yd_jieduan_A = 7

        if self.yd_jieduan_A == 7 and self.Gun_p_A.Y_l < self.Gun_p_A.mb_Y_l + int(self.y_A):
            self.Gun_p_A.Y_l = self.Gun_p_A.Y_l + 10
        elif self.yd_jieduan_A == 7 and self.Gun_p_A.Y_l > self.Gun_p_A.mb_Y_l + int(self.y_A):
            self.Gun_p_A.Y_l = self.Gun_p_A.Y_l - 10
        elif self.yd_jieduan_A == 7 and self.Gun_p_A.Y_l == self.Gun_p_A.mb_Y_l + int(self.y_A):
            self.yd_jieduan_A = 8

        if self.yd_jieduan_A == 8:
            self.Gun_p_A.R_l = self.Gun_p_A.R_l + float(self.re4_A)
            if self.Gun_p_A.R_l > 360:
                self.Gun_p_A.R_l = self.Gun_p_A.R_l - 360
            self.shuju_weizhi_A[5] = 1
            self.yd_jieduan_A = 9
            # self.timer.stop()

        self.shuju_weizhi_A[0] = self.Gun_p_A.X_l
        self.shuju_weizhi_A[1] = self.Gun_p_A.Y_l
        self.shuju_weizhi_A[2] = self.Gun_p_A.Z_l
        self.shuju_weizhi_A[3] = self.Gun_p_A.R_l
        self.shuju_weizhi_A[4] = self.Gun_p_A.ZhTai_l

        self.timeout_signal.emit(self.shuju_weizhi_A)

    def showtime_B(self):  # B枪坐标移动任务
        global Do_c
        global CH_zh
        if self.yd_jieduan_B == 0:
            self.shuju_weizhi_B[5] = 0
            # self.Gun_p_B.Z_l = self.Gun_p_B.mb_Z_l
            self.yd_jieduan_B = 1

        if self.yd_jieduan_B == 1 and self.Gun_p_B.X_l < self.Gun_p_B.mb_X_l:
            self.Gun_p_B.X_l = self.Gun_p_B.X_l + 10
        elif self.yd_jieduan_B == 1 and self.Gun_p_B.X_l > self.Gun_p_B.mb_X_l:
            self.Gun_p_B.X_l = self.Gun_p_B.X_l - 10
        elif self.yd_jieduan_B == 1 and self.Gun_p_B.X_l == self.Gun_p_B.mb_X_l:
            self.yd_jieduan_B = 2

        if self.yd_jieduan_B == 2:
            self.Gun_p_B.R_l = self.Gun_p_B.R_l + float(self.re_B)
            if self.Gun_p_B.R_l > 360:
                self.Gun_p_B.R_l = self.Gun_p_B.R_l - 360
            self.yd_jieduan_B = 3

        if self.yd_jieduan_B == 3 and self.Gun_p_B.Y_l < self.Gun_p_B.mb_Y_l:
            self.Gun_p_B.Y_l = self.Gun_p_B.Y_l + 10
        elif self.yd_jieduan_B == 3 and self.Gun_p_B.Y_l > self.Gun_p_B.mb_Y_l:
            self.Gun_p_B.Y_l = self.Gun_p_B.Y_l - 10
        elif self.yd_jieduan_B == 3 and self.Gun_p_B.Y_l == self.Gun_p_B.mb_Y_l:
            self.yd_jieduan_B = 4

        if self.yd_jieduan_B == 4:
            self.Gun_p_B.R_l = self.Gun_p_B.R_l + float(self.re2_B)
            if self.Gun_p_B.R_l > 360:
                self.Gun_p_B.R_l = self.Gun_p_B.R_l - 360
            self.yd_jieduan_B = 5

        if self.yd_jieduan_B == 5 and self.Gun_p_B.X_l < self.Gun_p_B.mb_X_l + int(self.x_B):
            self.Gun_p_B.X_l = self.Gun_p_B.X_l + 10
        elif self.yd_jieduan_B == 5 and self.Gun_p_B.X_l > self.Gun_p_B.mb_X_l + int(self.x_B):
            self.Gun_p_B.X_l = self.Gun_p_B.X_l - 10
        elif self.yd_jieduan_B == 5 and self.Gun_p_B.X_l == self.Gun_p_B.mb_X_l + int(self.x_B):
            self.yd_jieduan_B = 6

        if self.yd_jieduan_B == 6:
            self.Gun_p_B.R_l = self.Gun_p_B.R_l + float(self.re3_B)
            if self.Gun_p_B.R_l > 360:
                self.Gun_p_B.R_l = self.Gun_p_B.R_l - 360
            self.yd_jieduan_B = 7

        if self.yd_jieduan_B == 7 and self.Gun_p_B.Y_l < self.Gun_p_B.mb_Y_l + int(self.y_B):
            self.Gun_p_B.Y_l = self.Gun_p_B.Y_l + 10
        elif self.yd_jieduan_B == 7 and self.Gun_p_B.Y_l > self.Gun_p_B.mb_Y_l + int(self.y_B):
            self.Gun_p_B.Y_l = self.Gun_p_B.Y_l - 10
        elif self.yd_jieduan_B == 7 and self.Gun_p_B.Y_l == self.Gun_p_B.mb_Y_l + int(self.y_B):
            self.yd_jieduan_B = 8

        if self.yd_jieduan_B == 8:
            self.Gun_p_B.R_l = self.Gun_p_B.R_l + float(self.re4_B)
            if self.Gun_p_B.R_l > 360:
                self.Gun_p_B.R_l = self.Gun_p_B.R_l - 360
            self.yd_jieduan_B = 9
            self.shuju_weizhi_B[5] = 1
            # self.timer_B.stop()

        self.shuju_weizhi_B[0] = self.Gun_p_B.X_l
        self.shuju_weizhi_B[1] = self.Gun_p_B.Y_l
        self.shuju_weizhi_B[2] = self.Gun_p_B.Z_l
        self.shuju_weizhi_B[3] = self.Gun_p_B.R_l
        self.shuju_weizhi_B[4] = self.Gun_p_B.ZhTai_l
        self.timeout_signal_B.emit(self.shuju_weizhi_B)

    def showtime1(self):  # 下束记录任务
        global To_be_allocated_name
        self.event1.clear()
        with self.connection_pool.connection() as conn:
            with conn.cursor() as cursor:
                cursor.execute("SET TRANSACTION ISOLATION LEVEL SNAPSHOT")
                if self.start1_a:
                    time = QDateTime.currentDateTime()
                    # 将当前时间转换成字符串类型
                    datetimeDisplay = time.toString('yyyy-MM-dd hh:mm:ss.zzz')
                    # SQL插入语句，插入一行数据到KingTable1表
                    sql_insert_A = (
                        "INSERT INTO persons_A (日期时间, 坯组编号, 边号, [聚焦显示(V)], [偏压显示(V)], [灯丝显示(A)], [高压显示(KV)], [束流显示(MA)], "
                        "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, 枪室真空度, 焊室真空度, X坐标, Y坐标, Z坐标, R角度, "
                        "转台角度, 速度, 抽真空, 关门状态) VALUES (%s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d,%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s)")

                    polow = [datetimeDisplay, str("A待分配" + To_be_allocated_name), round(0),
                             round(uniform(self.Gun_p_A.ss_jujiao - 1, self.Gun_p_A.ss_jujiao + 1), 2),
                             round(uniform(self.Gun_p_A.ss_pianya - 1, self.Gun_p_A.ss_pianya + 1), 2),
                             round(uniform(self.Gun_p_A.ss_dengsi - 1, self.Gun_p_A.ss_dengsi + 1), 2),
                             round(uniform(self.Gun_p_A.ss_gaoya - 1, self.Gun_p_A.ss_gaoya + 1), 2),
                             round(uniform(self.Gun_p_A.ss_shuliu - 1, self.Gun_p_A.ss_shuliu + 1), 2),
                             round(uniform(self.Gun_p_A.ss_saomiaopl - 1, self.Gun_p_A.ss_saomiaopl + 1), 2),
                             round(uniform(self.Gun_p_A.ss_saomiaox - 1, self.Gun_p_A.ss_saomiaox + 1), 2),
                             round(uniform(self.Gun_p_A.ss_saomiaoy - 1, self.Gun_p_A.ss_saomiaoy + 1), 2),
                             round(uniform(self.Gun_p_A.ss_pianzhuanx - 1, self.Gun_p_A.ss_pianzhuanx + 1), 2),
                             round(uniform(self.Gun_p_A.ss_pianzhuany - 1, self.Gun_p_A.ss_pianzhuany + 1), 2),
                             round(uniform(self.Gun_p_A.ss_hezhoux - 1, self.Gun_p_A.ss_hezhoux + 1), 2),
                             round(uniform(self.Gun_p_A.ss_hezhouy - 1, self.Gun_p_A.ss_hezhouy + 1), 2),
                             round(uniform(self.Gun_p_A.ss_xiangsanx - 1, self.Gun_p_A.ss_xiangsanx + 1), 2),
                             round(uniform(self.Gun_p_A.ss_xiangsany - 1, self.Gun_p_A.ss_xiangsany + 1), 2),
                             round(self.Gun_p_A.ss_qszhkd), round(self.Gun_p_A.ss_hszhkd),
                             round(self.Gun_p_A.X_l, 3), round(self.Gun_p_A.Y_l, 3), round(self.Gun_p_A.Z_l, 3),
                             round(self.Gun_p_A.R_l, 3), round(self.Gun_p_A.ZhTai_l, 3),
                             round(200.123456, 3),
                             str(Do_c), str(CH_zh)]
                    try:
                        # 执行数据库，链接sqlserver，插入语句
                        cursor.execute(sql_insert_A, polow)
                        # 数据库提交事务
                        conn.commit()
                    except Exception as e:
                        conn.rollback()
                        print(f"Error: {e}")
                if self.start1_b:
                    time = QDateTime.currentDateTime()
                    # 将当前时间转换成字符串类型
                    datetimeDisplay = time.toString('yyyy-MM-dd hh:mm:ss.zzz')
                    # SQL插入语句，插入一行数据到KingTable1表
                    sql_insert_A = (
                        "INSERT INTO persons_B (日期时间, 坯组编号, 边号, [聚焦显示(V)], [偏压显示(V)], [灯丝显示(A)], [高压显示(KV)], [束流显示(MA)], "
                        "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, 枪室真空度, 焊室真空度, X坐标, Y坐标, Z坐标, R角度, "
                        "转台角度, 速度, 抽真空, 关门状态) VALUES (%s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %s, %s)")

                    polow = [datetimeDisplay, str("B待分配" + To_be_allocated_name), round(0),
                             round(uniform(self.Gun_p_B.ss_jujiao - 1, self.Gun_p_B.ss_jujiao + 1), 2),
                             round(uniform(self.Gun_p_B.ss_pianya - 1, self.Gun_p_B.ss_pianya + 1), 2),
                             round(uniform(self.Gun_p_B.ss_dengsi - 1, self.Gun_p_B.ss_dengsi + 1), 2),
                             round(uniform(self.Gun_p_B.ss_gaoya - 1, self.Gun_p_B.ss_gaoya + 1), 2),
                             round(uniform(self.Gun_p_B.ss_shuliu - 1, self.Gun_p_B.ss_shuliu + 1), 2),
                             round(uniform(self.Gun_p_B.ss_saomiaopl - 1, self.Gun_p_B.ss_saomiaopl + 1), 2),
                             round(uniform(self.Gun_p_B.ss_saomiaox - 1, self.Gun_p_B.ss_saomiaox + 1), 2),
                             round(uniform(self.Gun_p_B.ss_saomiaoy - 1, self.Gun_p_B.ss_saomiaoy + 1), 2),
                             round(uniform(self.Gun_p_B.ss_pianzhuanx - 1, self.Gun_p_B.ss_pianzhuanx + 1), 2),
                             round(uniform(self.Gun_p_B.ss_pianzhuany - 1, self.Gun_p_B.ss_pianzhuany + 1), 2),
                             round(uniform(self.Gun_p_B.ss_hezhoux - 1, self.Gun_p_B.ss_hezhoux + 1), 2),
                             round(uniform(self.Gun_p_B.ss_hezhouy - 1, self.Gun_p_B.ss_hezhouy + 1), 2),
                             round(uniform(self.Gun_p_B.ss_xiangsanx - 1, self.Gun_p_B.ss_xiangsanx + 1), 2),
                             round(uniform(self.Gun_p_B.ss_xiangsany - 1, self.Gun_p_B.ss_xiangsany + 1), 2),
                             round(self.Gun_p_B.ss_qszhkd), round(self.Gun_p_B.ss_hszhkd),
                             round(self.Gun_p_B.X_l, 3), round(self.Gun_p_B.Y_l, 3), round(self.Gun_p_B.Z_l, 3),
                             round(self.Gun_p_B.R_l, 3), round(self.Gun_p_B.ZhTai_l, 3),
                             round(200.123456, 3),
                             str(Do_c), str(CH_zh)]
                    try:
                        # 执行数据库，链接sqlserver，插入语句
                        cursor.execute(sql_insert_A, polow)
                        # 数据库提交事务
                        conn.commit()
                    except Exception as e:
                        conn.rollback()
                        print(f"Error: {e}")
                cursor.close()
                self.event1.set()

    def showtime2_A(self):  # A实时数据图像更新
        if self.Display_Range:
            # 当前时间QDateTime类型
            datetimeDisplay = QDateTime.currentDateTime()
            data1 = [[datetimeDisplay,
                     round(uniform(self.Gun_p_A.ss_jujiao - 1, self.Gun_p_A.ss_jujiao + 1), 2),
                     round(uniform(self.Gun_p_A.ss_pianya - 1, self.Gun_p_A.ss_pianya + 1), 2),
                     round(uniform(self.Gun_p_A.ss_dengsi - 1, self.Gun_p_A.ss_dengsi + 1), 2),
                     round(uniform(self.Gun_p_A.ss_gaoya - 1, self.Gun_p_A.ss_gaoya + 1), 2),
                     round(uniform(self.Gun_p_A.ss_shuliu - 1, self.Gun_p_A.ss_shuliu + 1), 2),
                     round(uniform(self.Gun_p_A.ss_saomiaopl - 1, self.Gun_p_A.ss_saomiaopl + 1), 2),
                     round(uniform(self.Gun_p_A.ss_saomiaox - 1, self.Gun_p_A.ss_saomiaox + 1), 2),
                     round(uniform(self.Gun_p_A.ss_saomiaoy - 1, self.Gun_p_A.ss_saomiaoy + 1), 2),
                     round(uniform(self.Gun_p_A.ss_pianzhuanx - 1, self.Gun_p_A.ss_pianzhuanx + 1), 2),
                     round(uniform(self.Gun_p_A.ss_pianzhuany - 1, self.Gun_p_A.ss_pianzhuany + 1), 2),
                     round(uniform(self.Gun_p_A.ss_hezhoux - 1, self.Gun_p_A.ss_hezhoux + 1), 2),
                     round(uniform(self.Gun_p_A.ss_hezhouy - 1, self.Gun_p_A.ss_hezhouy + 1), 2),
                     round(uniform(self.Gun_p_A.ss_xiangsanx - 1, self.Gun_p_A.ss_xiangsanx + 1), 2),
                     round(uniform(self.Gun_p_A.ss_xiangsany - 1, self.Gun_p_A.ss_xiangsany + 1), 2),
                     round(self.Gun_p_A.ss_qszhkd), round(self.Gun_p_A.ss_hszhkd),
                     round(self.Gun_p_A.R_l, 3), round(self.Gun_p_A.ZhTai_l, 3),
                     round(self.Gun_p_A.X_l, 3), round(self.Gun_p_A.Y_l, 3), round(self.Gun_p_A.Z_l, 3)]]
            data1 = np.array(data1)
            self.timeout_duqu_sql.emit(data1)
        else:
            start_time = times.time()
            self.event1.wait(timeout=0.5)   # 阻塞等待，等待数据库写完成
            with self.connection_pool.connection() as conn:
                with conn.cursor() as cursor:
                    cursor.execute("SET TRANSACTION ISOLATION LEVEL SNAPSHOT")
                    try:
                    # A枪数据更新
                        cursor.execute(
                            "SELECT 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
                            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
                            "枪室真空度,焊室真空度,R角度,转台角度,X坐标,Y坐标,Z坐标 FROM persons_A WHERE 日期时间 > %s",
                            self.old_time_A.toString('yyyy-MM-dd hh:mm:ss.zzz'))
                        data1 = cursor.fetchall()
                        print(len(data1))
                        conn.commit()
                        # 获取查询结果（旧时间后所有数据）
                        if data1:
                            data1 = np.array(data1)
                            for i in data1:
                                i[0] = QDateTime(i[0].date(), i[0].time())  # 数据库datatime 转为 QDateTime
                            self.timeout_duqu_sql.emit(data1)
                        else:
                            print("No data found.")
                    except Exception as e:
                        conn.rollback()
                        print(f"Error: {e}")
                    finally:
                        cursor.close()
            print(f"A图像数据处理 执行耗时: {times.time() - start_time:.6f}秒")  # 输出方法耗时

    def showtime2_B(self):  # B实时数据图像更新
        if self.Display_Range:
            # 当前时间QDateTime类型
            datetimeDisplay = QDateTime.currentDateTime()
            data1 = [[datetimeDisplay,
                     round(uniform(self.Gun_p_B.ss_jujiao - 1, self.Gun_p_B.ss_jujiao + 1), 2),
                     round(uniform(self.Gun_p_B.ss_pianya - 1, self.Gun_p_B.ss_pianya + 1), 2),
                     round(uniform(self.Gun_p_B.ss_dengsi - 1, self.Gun_p_B.ss_dengsi + 1), 2),
                     round(uniform(self.Gun_p_B.ss_gaoya - 1, self.Gun_p_B.ss_gaoya + 1), 2),
                     round(uniform(self.Gun_p_B.ss_shuliu - 1, self.Gun_p_B.ss_shuliu + 1), 2),
                     round(uniform(self.Gun_p_B.ss_saomiaopl - 1, self.Gun_p_B.ss_saomiaopl + 1), 2),
                     round(uniform(self.Gun_p_B.ss_saomiaox - 1, self.Gun_p_B.ss_saomiaox + 1), 2),
                     round(uniform(self.Gun_p_B.ss_saomiaoy - 1, self.Gun_p_B.ss_saomiaoy + 1), 2),
                     round(uniform(self.Gun_p_B.ss_pianzhuanx - 1, self.Gun_p_B.ss_pianzhuanx + 1), 2),
                     round(uniform(self.Gun_p_B.ss_pianzhuany - 1, self.Gun_p_B.ss_pianzhuany + 1), 2),
                     round(uniform(self.Gun_p_B.ss_hezhoux - 1, self.Gun_p_B.ss_hezhoux + 1), 2),
                     round(uniform(self.Gun_p_B.ss_hezhouy - 1, self.Gun_p_B.ss_hezhouy + 1), 2),
                     round(uniform(self.Gun_p_B.ss_xiangsanx - 1, self.Gun_p_B.ss_xiangsanx + 1), 2),
                     round(uniform(self.Gun_p_B.ss_xiangsany - 1, self.Gun_p_B.ss_xiangsany + 1), 2),
                     round(self.Gun_p_B.ss_qszhkd), round(self.Gun_p_B.ss_hszhkd),
                     round(self.Gun_p_B.R_l, 3), round(self.Gun_p_B.ZhTai_l, 3),
                     round(self.Gun_p_B.X_l, 3), round(self.Gun_p_B.Y_l, 3), round(self.Gun_p_B.Z_l, 3)]]
            data1 = np.array(data1)
            self.timeout_duqu_sql_B.emit(data1)
        else:
            start_time = times.time()
            self.event1.wait(timeout=0.5)  # 阻塞等待，等待数据库写完成
            with self.connection_pool.connection() as conn:
                with conn.cursor() as cursor:
                    cursor.execute("SET TRANSACTION ISOLATION LEVEL SNAPSHOT")
                    try:
                        # B枪数据更新
                        cursor.execute(
                            "SELECT 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
                            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
                            "枪室真空度,焊室真空度,R角度,转台角度,X坐标,Y坐标,Z坐标  FROM persons_B WHERE 日期时间 > %s",
                            self.old_time_B.toString('yyyy-MM-dd hh:mm:ss.zzz'))
                        data1 = cursor.fetchall()
                        print(len(data1))
                        conn.commit()
                        # 获取查询结果（返回最后一行数据）
                        if data1:
                            data1 = np.array(data1)
                            for i in data1:
                                i[0] = QDateTime(i[0].date(), i[0].time())  # 数据库datatime 转为 QDateTime
                            self.timeout_duqu_sql_B.emit(data1)
                        else:
                            print("No data found.")
                    except Exception as e:
                        conn.rollback()
                        print(f"Error: {e}")
                    finally:
                        cursor.close()
            print(f"B图像数据处理 执行耗时: {times.time() - start_time:.6f}秒")  # 输出方法耗时

    def showtime3(self):
        # 步骤一：读取PLC内容
        # 步骤二：读取A枪数控设备内容
        # 步骤三：读取B枪数控设备内容
        # 步骤四：判断设备状态：在线状态、枪位置、转台位置、设备报警状况。
        # print(self.Gun_p_A.ZhTai_old_l,self.Gun_p_A.ZhTai_l)
        if self.Gun_p_A.ZhTai_old_l != self.Gun_p_A.ZhTai_l:
            self.ZhTai_change_A(self.time_xyz_A,
                                np.array([self.a_r_x, 0, self.a_r_y]),
                                self.Gun_p_A.ZhTai_l - self.Gun_p_A.ZhTai_old_l)  # 重新绘制点位位置
            self.Gun_p_A.ZhTai_old_l = self.Gun_p_A.ZhTai_l
        if self.Gun_p_B.ZhTai_old_l != self.Gun_p_B.ZhTai_l:
            self.ZhTai_change_B(self.time_xyz_B,
                                np.array([self.b_r_x, 0, self.b_r_y]),
                                self.Gun_p_B.ZhTai_l - self.Gun_p_B.ZhTai_old_l)  # 重新绘制点位位置
            self.Gun_p_B.ZhTai_old_l = self.Gun_p_B.ZhTai_l

    # -------------------转台变化事件------------------
    def ZhTai_change_A(self, original_points, center, angle):
        # original_points需旋转的坐标集合，center为旋转中心，angle为旋转角度
        self.time_xyz_A = batch_rotate_around_y(original_points, center, angle)
        self.t_xyz_rd_A.emit(self.time_xyz_A)


    def ZhTai_change_B(self, original_points, center, angle):
        print(center)
        self.time_xyz_B = batch_rotate_around_y(original_points, center, angle)
        self.t_xyz_rd_B.emit(self.time_xyz_B)


#-----------------------判断Y轴范围是否变化------------------------
def range_exceeds(min_y, max_y, min_y_A, max_y_A, axis_y_A):
    if_chfw = 0  # 是否改变范围的变量
    if min_y < min_y_A:
        min_y_A = min_y
        if_chfw = 1
    if max_y > max_y_A:  # 判断Y轴范围是否有变
        max_y_A = max_y
        if_chfw = 1
    if if_chfw:
        axis_y_A.setRange(min_y_A - 10, max_y_A + 10)
        if_chfw = 0
    return min_y_A, max_y_A


# -----------------界面逻辑------------------
class ui_main(Ui_MainWindow, QMainWindow):
    def __init__(self):
        super().__init__()
        # 设置关闭时自动删除对象
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        # 数据库操作对象注册
        self.conn = pymssql.connect(server=servermy, port=portmy, user=usermy, password=passwordmy,
                                    database=databasemy, charset='utf8')
        # self.label_20.setStyleSheet("color: green")
        # self.label_20.setText('数据库链接成功')
        self.cursor = self.conn.cursor()
        self.cursor.execute("SET TRANSACTION ISOLATION LEVEL SNAPSHOT")  # 设置事务隔离级别，读取历史提交数据，避免锁竞争
        self.conn.autocommit(True)  # 设置是否自动提交事务

        self.timer = QTimer()    # A枪运动坐标变化
        self.timer_B = QTimer()  # B枪运动坐标变化
        self.old_time_B = None
        self.old_time_A = None
        # 用于记录当前选中的按钮
        self.current_button = None
        self.USER_DATA_FILE = 'H_S_JSON/sqls.json'  # json数据文件名称
        self.setupUi(self)

        self.runtime_3D_init()   # 3D实时图像初始化
        self.runtime_2D_init()   # 2D实时图像初始化
        self.preset_data_init()  # 预设数据初始化
        self.time_Thread_init()  # 定时器与多线程初始化
        self.event_init()        # 窗口事件绑定初始化

        # self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)  # 无边框窗口

        # A枪与B枪参数对象
        # ------------------------窗口事件-----------------------
        # 开始进行定时任务
        # self.timer3.start(cycle_1*5)        # 定时器运行开始并时间设定
        # print("init overd")

    # --------------实时数据初始化更新方法------------------
    # 3D焊接过程实时显示初始化
    def runtime_3D_init(self):
        # ---------------------实时3D图像初始化---------------------
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            key_v_data = json.load(file)
        self.surface = CustomScatter()  # 3D容器
        self.surface.setShadowQuality(QAbstract3DGraph.ShadowQuality.ShadowQualityNone)    # 去除绘图对象的阴影
        axis = self.surface.axisX()  # 三轴初始化
        axis.setTitle("X")
        axis.setTitleVisible(True)
        axis.setRange(key_v_data["3Dline"]["X_min"], key_v_data["3Dline"]["X_max"])  # 设置X轴范围
        axis = self.surface.axisY()
        axis.setTitle("Z")
        axis.setTitleVisible(True)
        axis.setRange(key_v_data["3Dline"]["Z_min"], key_v_data["3Dline"]["Z_max"])
        axis = self.surface.axisZ()
        axis.setTitle("Y")
        axis.setTitleVisible(True)
        axis.setRange(key_v_data["3Dline"]["Y_min"], key_v_data["3Dline"]["Y_max"])
        self._container = QWidget.createWindowContainer(self.surface)
        self._container.setFixedSize(250, 400)  # 设置3D图表大小
        self._container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._container.setFocusPolicy(Qt.StrongFocus)

        self.verticalLayout.addWidget(self._container)  # 多选按钮上方布局内添加3D图表
        self.data_3D_A = []
        self.data_3D_B = []
        self.data_xyz_A = []
        self.data_xyz_B = []
        self.data_nowp_A = []
        self.data_nowp_B = []
        self.data_dianhan_A = []
        self.data_dianhan_B = []
        self.data_police_c = []
        self.series_chocked = None
        self.series_chock_old = None
        # 元素类型	   曲线A	           曲线B	            异常点
        # 主曲线	  #1F77B4 (钴蓝)	   #FF7F0E (橙红)	      -
        # 当前点	  #4C72B0	       #D55E00	         #D62728 (正红)
        # 电焊点	  #2CA02C (青绿)	   #9467BD (紫)	          -

        # A绘制点
        self.series_A = QScatter3DSeries()  # 3D数据框架
        self.series_A.setBaseColor(QColor(44, 95,
                                          138))  # A设置颜色QColor(31, 119, 180)    点QColor(76, 114, 176)     点焊QColor(44, 160, 44)     报警点QColor(214, 39, 40)
        self.series_A.setItemSize(
            0.05)  # 设置点大小   # B设置颜色QColor(255, 127, 14)    点QColor(213, 94, 0)       点焊QColor(148, 103, 189)
        self.series_A.setMeshSmooth(True)  # 设置平滑
        self.series_A.setMesh(QAbstract3DSeries.MeshPoint)  # 设置形状 - 指向点
        # B绘制点
        self.series_B = QScatter3DSeries()  # 3D数据框架
        self.series_B.setBaseColor(QColor(235, 168, 27))
        self.series_B.setItemSize(0.05)  # 设置点大小
        self.series_B.setMeshSmooth(True)  # 设置平滑
        self.series_B.setMesh(QAbstract3DSeries.MeshPoint)  # 设置形状 - 指向点
        # A当前点
        self.nowp_A = QScatter3DSeries()  # 3D数据框架
        self.nowp_A.setBaseColor(QColor(148, 145, 182))
        self.nowp_A.setItemSize(0.08)  # 设置点大小
        self.nowp_A.setMeshSmooth(True)  # 设置平滑
        self.nowp_A.setMesh(QAbstract3DSeries.MeshSphere)  # 设置形状 - 指向点
        # B当前点
        self.nowp_B = QScatter3DSeries()  # 3D数据框架
        self.nowp_B.setBaseColor(QColor(249, 225, 126))
        self.nowp_B.setItemSize(0.08)  # 设置点大小
        self.nowp_B.setMeshSmooth(True)  # 设置平滑
        self.nowp_B.setMesh(QAbstract3DSeries.MeshSphere)  # 设置形状 - 指向点
        # A 点焊点
        self.dianhan_A = QScatter3DSeries()  # 3D数据框架
        self.dianhan_A.setBaseColor(QColor(148, 145, 182))
        self.dianhan_A.setItemSize(0.08)  # 设置点大小
        self.dianhan_A.setMeshSmooth(True)  # 设置平滑
        self.dianhan_A.setMesh(QAbstract3DSeries.MeshPoint)  # 设置形状 - 指向点
        # B 点焊点
        self.dianhan_B = QScatter3DSeries()  # 3D数据框架
        self.dianhan_B.setBaseColor(QColor(249, 225, 126))
        self.dianhan_B.setItemSize(0.08)  # 设置点大小
        self.dianhan_B.setMeshSmooth(True)  # 设置平滑
        self.dianhan_B.setMesh(QAbstract3DSeries.MeshPoint)  # 设置形状 - 指向点
        # 报警点
        self.police_c = QScatter3DSeries()  # 3D数据框架
        self.police_c.setBaseColor(QColor(193, 39, 45))
        self.police_c.setItemSize(0.05)  # 设置点大小
        self.police_c.setMeshSmooth(True)  # 设置平滑
        self.police_c.setMesh(QAbstract3DSeries.MeshArrow)  # 设置形状 - 指向点
        # 鼠标指示点
        self.zhishi_c = QScatter3DSeries()  # 3D数据框架
        self.zhishi_c.setBaseColor(QColor(255, 255, 255))
        self.zhishi_c.setItemSize(0.05)  # 设置点大小
        self.zhishi_c.setMeshSmooth(True)  # 设置平滑
        self.zhishi_c.setMesh(QAbstract3DSeries.MeshSphere)  # 设置形状 - 指向点

        # self.series.dataProxy().resetArray(self.data_3D)  # 修改这里，直接传递data列表
        self.surface.addSeries(self.series_A)
        self.surface.addSeries(self.series_B)
        self.surface.addSeries(self.nowp_A)
        self.surface.addSeries(self.nowp_B)
        self.surface.addSeries(self.dianhan_A)
        self.surface.addSeries(self.dianhan_B)
        self.surface.addSeries(self.police_c)
        self.surface.addSeries(self.zhishi_c)

        self.surface.selectedSeriesChanged.connect(self.on_scatter_point_clicked)
        # 连接场景点击信号
        self.surface.clickValidated.connect(self.handle_viewport_click)
        # -----------------------------------------------------

    # 2D实时显示初始化
    def runtime_2D_init(self):
        # ---------------------实时2维图像初始化---------------------
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/legend.json'
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            self.key_v_data = json.load(file)
        self.indexed_items = list(self.key_v_data.items())
        # 将字典转换为一个列表，其中每个元素是一个键值对元组

        # 创建 QChart 对象
        self.line_chart_A = QChart()
        self.line_chart_A.setMargins(QMargins(0, 0, 0, 0))  # 左、上、右、下全为0
        self.line_chart_A.setDropShadowEnabled(False)  # 关闭阴影
        self.line_chart_A.setAnimationOptions(QChart.NoAnimation)  # 关闭动画

        self.line_chart_B = QChart()
        self.line_chart_B.setMargins(QMargins(0, 0, 0, 0))  # 左、上、右、下全为0
        self.line_chart_B.setDropShadowEnabled(False)  # 关闭阴影
        self.line_chart_B.setAnimationOptions(QChart.NoAnimation)  # 关闭动画

        self.colors = [  # 不同曲线对应的颜色
            QColor(255, 0, 0), QColor(0, 255, 0), QColor(0, 0, 255), QColor(210, 105, 30),
            QColor(255, 97, 0), QColor(0, 199, 140), QColor(255, 0, 255), QColor(153, 51, 250),
            QColor(0, 114, 206), QColor(213, 94, 0), QColor(0, 158, 115), QColor(230, 159, 0),
            QColor(153, 0, 255), QColor(128, 128, 128), QColor(0, 180, 180), QColor(85, 107, 47),
            QColor(139, 69, 19), QColor(8, 46, 84)]
        self.colors_mc = [  # 不同多选框对应的颜色
            "color: #FF0000", "color: #00FF00", "color: #0000FF", "color: #D2691E",
            "color: #FF6100", "color: #00C78C", "color: #FF00FF", "color: #9933FA",
            "color: #0072CE", "color: #D55E00", "color: #009E73", "color: #E69F00",
            "color: #9900FF", "color: #808080", "color: #00B4B4", "color: #556B2F",
            "color: #8B4513", "color: #082E54"]
        self.min_y_A = 0
        self.max_y_A = 0
        self.min_y_B = 0
        self.max_y_B = 0
        self.chart_line_A = []  # 曲线对象集合, 用于实时显示时绘制的曲线对象
        self.chart_line_B = []  # 曲线对象集合, 用于实时显示时绘制的曲线对象
        self.shuju_zidian_A = {}  # 数据字典存储， 用于云框显示鼠标处数据值
        self.shuju_zidian_B = {}  # 数据字典存储， 用于云框显示鼠标处数据值
        self.time_xyz_A = np.empty((0, 4))  # 日期与坐标存储， 用于3D图像鼠标点显示
        self.time_xyz_B = np.empty((0, 4))  # 日期与坐标存储， 用于3D图像鼠标点显示
        self.pen_style_A = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]  # 曲线笔模式状态，1：实线，0：虚线  A枪
        self.pen_style_B = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]  # 曲线笔模式状态，1：实线，0：虚线  B枪
        # 创建 QDateTimeAxis A枪 实例并设置格式
        self.axis_x_A = QDateTimeAxis()
        self.axis_x_A.setFormat("hh:mm:ss")  # 设置日期时间格式
        self.axis_x_A.setTickCount(5)
        self.axis_x_A.setTickCount(15)  # 设置x轴间隔数量
        self.axis_x_A.setLabelsAngle(10)  # 设置显示方向，旋转角度
        # 创建 QDateTimeAxis A枪 实例并设置格式
        self.axis_x_B = QDateTimeAxis()
        self.axis_x_B.setFormat("hh:mm:ss")  # 设置日期时间格式
        self.axis_x_B.setTickCount(5)
        self.axis_x_B.setTickCount(15)  # 设置x轴间隔数量
        self.axis_x_B.setLabelsAngle(10)  # 设置显示方向，旋转角度
        # 创建 QValueAxis A枪 实例并设置 y 轴范围
        self.axis_y_A = QValueAxis()
        # 创建 QValueAxis A枪 实例并设置 y 轴范围
        self.axis_y_B = QValueAxis()

        self.fanwei = self.verticalSlider.value()  # 获得滑动条设置的显示时间范围

        opengl_widget = QOpenGLWidget()
        opengl_widget.setStyleSheet("background: transparent;")  # 关键修改

        self.line_chart_A.setTitle("A枪数据")
        self.line_chart_A.setAnimationOptions(QChart.SeriesAnimations)
        self.line_chart_B.setTitle("B枪数据")
        self.line_chart_B.setAnimationOptions(QChart.SeriesAnimations)

        # A枪显示界面对象
        self.chart_view_A = chartview.ChartView(self.line_chart_A, self.indexed_items, self.shuju_zidian_A, self.max_y_A)  # 这里假设你已定义了 ChartView 类
        self.chart_view_A.chart().legend().setVisible(False)
        self.chart_view_A.setRenderHint(QPainter.Antialiasing, False)  # 关闭抗锯齿
        # B枪显示界面对象
        self.chart_view_B = chartview.ChartView(self.line_chart_B, self.indexed_items, self.shuju_zidian_B, self.max_y_B)  # 这里假设你已定义了 ChartView 类
        self.chart_view_B.chart().legend().setVisible(False)
        self.chart_view_B.setRenderHint(QPainter.Antialiasing, False)  # 关闭抗锯齿

        self.chart_view_A.time_key = self.update_R_time_data_ini_A()  # 实时数据初始化方法
        self.chart_view_B.time_key = self.update_R_time_data_ini_B()  # 实时数据初始化方法
        self.chart_view_A.y_max = self.max_y_A
        self.chart_view_B.y_max = self.max_y_B

        self.verticalLayout_2.addWidget(self.chart_view_A)  # 布局内添加A图表显示窗口

        self.verticalLayout_2.addWidget(self.chart_view_B)  # 布局内添加B图表显示窗口

    # 定时器与多线程初始化
    def time_Thread_init(self):
        # ----------------------多线程初始化---------------------
        self.timer3 = QTimer()   # 用于更新二维图表范围、更新显示数据数组大小
        self.timer4 = QTimer()   # 用于实时数据的大小更新操作（5分钟更新数据大小，直接从数据库中提取更新）
        # self.timer4 = QTimer()   # 用于实时
        self.timer3.timeout.connect(self.showtime3)
        self.timer4.timeout.connect(self.showtime4)
        self.time3_jd = 0                                           # 时间计数器，用于判断是否需要更新二维数据
        self.time4_last_time = QDateTime.currentDateTime()          # 上一次的时间保存的时间，间隔五分钟
        self.big_arr_a = 0                                          # 已存储的数据大小 A
        self.big_arr_b = 0                                          # 已存储的数据大小 B
        if self.checkBox_20.isChecked() == True:
            self.timer3.start(cycle_1 * 5)
        # 创建子线程 和 Worker
        self.thread = QThread()
        self.worker = TimerWorker()
        self.worker.moveToThread(self.thread)
        self.thread.start()
        self.worker.time_start2_A.emit(cycle_1, self.old_time_A)    # 多线程中的A 实时图像更新
        self.worker.time_start2_B.emit(cycle_1, self.old_time_B)    # 多线程中的B 实时图像更新
        self.timer4.start(cycle_1 * 300)
        # 多线程中的旋转 实时检测
        self.worker.time_start_zht.emit(cycle_1 * 3, int(self.lineEdit1_68.text()), int(self.lineEdit1_69.text()), int(self.lineEdit1_70.text()), int(self.lineEdit1_71.text()))

        # 连接信号与槽
        self.worker.timeout_signal.connect(self.handle_timeout)
        self.worker.timeout_signal_B.connect(self.handle_timeout_B)
        self.worker.timeout_duqu_sql.connect(self.showtime2_A)
        self.worker.timeout_duqu_sql_B.connect(self.showtime2_B)
        self.worker.t_xyz_rd_A.connect(self.showtime3_A)
        self.worker.t_xyz_rd_B.connect(self.showtime3_B)

        if self.radioButton_3.isChecked():            # 更新显示范围设置
            self.worker.D_Range_IN.emit(0)
        elif self.radioButton_4.isChecked():
            self.worker.D_Range_IN.emit(1)

        if self.radioButton_5.isChecked():            # 更新保存范围设置
            self.worker.S_scope_IN.emit(0)
        elif self.radioButton_6.isChecked():
            self.worker.S_scope_IN.emit(1)
        elif self.radioButton_7.isChecked():
            self.worker.S_scope_IN.emit(2)

    # 附属线程定时任务开启
    @Slot(object)
    def handle_timeout(self, data):
        self.label_59.setText(str(data[0]))
        self.label_62.setText(str(data[1]))
        self.label_70.setText(str(data[2]))
        self.label_64.setText(str(data[3]))
        self.label_67.setText(str(data[4]))
        if data[5]:
            self.label_91.setStyleSheet("color: green")
            self.label_91.setText('移动完成')

    @Slot()
    def handle_timeout_B(self, data):
        self.label_121.setText(str(data[0]))
        self.label_120.setText(str(data[1]))
        self.label_110.setText(str(data[2]))
        self.label_118.setText(str(data[3]))
        self.label_114.setText(str(data[4]))
        if data[5]:
            self.label_130.setStyleSheet("color: green")
            self.label_130.setText('移动完成')

    # 窗口事件绑定初始化
    def event_init(self):
        # ---------------------输入框数据初始化--------------------
        self.lineEdit1_15.setText(str(cycle_1))
        self.textEdit1_3.setEnabled(0)  # cnc输出文本框设置为不可更改
        # 下拉框数据填入

        # 输入框事件绑定
        self.lineEdit1.editingFinished.connect(self.lineEdit1_change)        # opcurl 输入框改变动作函数绑定
        self.lineEdit1_2.editingFinished.connect(self.lineEdit1_2_change)    # opc 账号输入框改变动作函数绑定
        self.lineEdit1_3.editingFinished.connect(self.lineEdit1_3_change)    # opc 密码输入框改变动作函数绑定
        self.lineEdit1_5.editingFinished.connect(self.lineEdit1_5_change)    # A枪CNC 连接地址输入框改变动作函数绑定
        self.lineEdit1_6.editingFinished.connect(self.lineEdit1_6_change)    # A枪CNC 端口输入框改变动作函数绑定
        self.lineEdit1_8.editingFinished.connect(self.lineEdit1_8_change)    # B枪CNC 连接地址输入框改变动作函数绑定
        self.lineEdit1_7.editingFinished.connect(self.lineEdit1_7_change)    # B枪CNC 端口输入框改变动作函数绑定
        self.lineEdit1_9.editingFinished.connect(self.lineEdit1_9_change)    # 数据库库名称输入框改变动作函数绑定
        self.lineEdit1_10.editingFinished.connect(self.lineEdit1_10_change)  # 数据库端口输入框改变动作函数绑定
        self.lineEdit1_11.editingFinished.connect(self.lineEdit1_11_change)  # 数据库账号名称输入框改变动作函数绑定
        self.lineEdit1_4.editingFinished.connect(self.lineEdit1_4_change)    # 数据库密码输入框改变动作函数绑定
        self.lineEdit1_12.editingFinished.connect(self.lineEdit1_12_change)  # 数据库表名称输入框改变动作函数绑定
        self.lineEdit1_13.editingFinished.connect(self.lineEdit1_13_change)  # 数据库新建库名称输入框改变动作函数绑定
        self.lineEdit1_14.editingFinished.connect(self.lineEdit1_14_change)  # 数据库新建表名称输入框改变动作函数绑定
        self.textEdit1.textChanged.connect(self.textEdit1_change)            # 新建数据表内容被更改事件绑定
        self.lineEdit1_15.editingFinished.connect(self.lineEdit1_15_change)  # 执行周期毫秒数输入框改变动作函数绑定
        self.lineEdit1_54.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("X_min", self.lineEdit1_54))  # 3D X轴显示范围设置
        self.lineEdit1_55.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("X_max", self.lineEdit1_55))  # 3D X轴显示范围设置
        self.lineEdit1_56.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("Y_min", self.lineEdit1_56))  # 3D Y轴显示范围设置
        self.lineEdit1_57.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("Y_max", self.lineEdit1_57))  # 3D Y轴显示范围设置
        self.lineEdit1_58.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("Z_min", self.lineEdit1_58))  # 3D Z轴显示范围设置
        self.lineEdit1_59.editingFinished.connect(
            lambda: self.lineEdit1_3Dfanwei_change("Z_max", self.lineEdit1_59))  # 3D Z轴显示范围设置

        self.lineEdit1_72.editingFinished.connect(
            lambda: self.lineEdit1_72_change("Real_time_data_length", self.lineEdit1_72))  # 实时数据存储长度

        # 按钮事件绑定
        self.actiondenglu.triggered.connect(self.actiondenglu_clicked)    # 菜单登录按钮点击事件-弹出输出窗口
        self.pushButton.clicked.connect(self.pushButton_clicked)          # 实时数据缩放归位，一键归位按钮
        self.pushButton1.clicked.connect(self.pushButton1_clicked)        # opcua连接按钮被按下时动作函数绑定
        self.pushButton1_2.clicked.connect(self.pushButton1_2_clicked)    # opcua断开按钮被按下时动作函数绑定
        self.pushButton1_13.clicked.connect(self.pushButton1_13_clicked)  # opcua获取节点按钮被按下时动作函数绑定
        self.pushButton1_4.clicked.connect(self.pushButton1_4_clicked)    # A枪CNC连接按钮被按下时动作函数绑定
        self.pushButton1_3.clicked.connect(self.pushButton1_3_clicked)    # A枪CNC断开按钮被按下时动作函数绑定
        self.pushButton1_6.clicked.connect(self.pushButton1_6_clicked)    # B枪CNC连接按钮被按下时动作函数绑定
        self.pushButton1_5.clicked.connect(self.pushButton1_5_clicked)    # B枪CNC断开按钮被按下时动作函数绑定
        self.pushButton1_15.clicked.connect(self.pushButton1_15_clicked)  # CNC数据获取按钮被按下时动作函数绑定
        self.pushButton1_8.clicked.connect(self.pushButton1_8_clicked)    # 数据库连接按钮被按下时动作函数绑定
        self.pushButton1_7.clicked.connect(self.pushButton1_7_clicked)    # 数据库断开按钮被按下时动作函数绑定
        self.pushButton1_9.clicked.connect(self.pushButton1_9_clicked)    # 新建数据库新建按钮被按下时动作函数绑定
        self.pushButton1_10.clicked.connect(self.pushButton1_10_clicked)  # 新建数据表新建按钮被按下时动作函数绑定
        self.pushButton1_26.clicked.connect(self.pushButton1_26_clicked)  # 生产报表条件查询按钮事件绑定
        self.pushButton1_21.clicked.connect(self.pushButton1_21_clicked)  # 生产报表时间查询按钮事件绑定
        self.pushButton1_17.clicked.connect(self.pushButton1_17_clicked)  # 详情数据数据库时间查询按钮被按下时动作函数绑定
        self.pushButton1_27.clicked.connect(self.pushButton1_27_clicked)  # 详情数据数据库条件查询按钮被按下时动作函数绑定
        self.pushButton1_18.clicked.connect(self.pushButton1_18_clicked)  # 数据库查询表格打印按钮被按下时动作函数绑定
        self.pushButton1_22.clicked.connect(self.pushButton1_22_clicked)  # 生产数据表格PDF打印按钮被按下时动作函数绑定
        self.pushButton1_25.clicked.connect(self.pushButton1_25_clicked)  # 原料数据表格PDF打印按钮被按下时动作函数绑定
        self.pushButton1_19.clicked.connect(self.export_to_excel)         # 详细数据——数据库查询表格输出excel被按下时动作函数绑定
        self.pushButton1_23.clicked.connect(self.shchen_to_excel)         # 生产数据——数据库查询表格输出excel被按下时动作函数绑定
        self.pushButton1_24.clicked.connect(self.pushButton1_24_clicked)  # 历史数据图像窗口弹出
        self.pushButton1_28.clicked.connect(self.pushButton1_28_clicked)  # 待分配数据按临时数据查询
        self.pushButton1_29.clicked.connect(self.pushButton1_29_clicked)  # 待分配数据按时间段查询
        self.pushButton1_30.clicked.connect(self.pushButton1_30_clicked)  # 待分配数据重新分配，弹出生产数据输入界面窗口
        self.pushButton_2.clicked.connect(self.pushButton_2_clicked)      # 3D图像缩放按钮被按下，窗口弹出

        # 临时模拟按钮
        self.pushButton1_31.clicked.connect(self.pushButton1_31_clicked)  # 开门按钮，根据关门时到现在为止的数据生成生产以及原料数据，进行分配
        self.pushButton1_32.clicked.connect(self.pushButton1_32_clicked)  # 放气按钮，放气成功之后才能开门
        self.pushButton1_33.clicked.connect(self.pushButton1_33_clicked)  # A 聚焦开启按钮，点一次开启，再点一次关闭
        self.pushButton1_34.clicked.connect(self.pushButton1_34_clicked)  # A 偏压开启按钮，点一次开启，再点一次关闭
        self.pushButton1_35.clicked.connect(self.pushButton1_35_clicked)  # A 灯丝开启按钮，点一次开启，再点一次关闭
        self.pushButton1_36.clicked.connect(self.pushButton1_36_clicked)  # A 高压开启按钮，点一次开启，再点一次关闭
        self.pushButton1_37.clicked.connect(self.pushButton1_37_clicked)  # A 束流开启按钮，点一次开启，再点一次关闭
        self.pushButton1_38.clicked.connect(self.pushButton1_38_clicked)  # A 移动开启按钮，点一次开启执行一轮移动，依次按输入信息增加
        self.pushButton1_48.clicked.connect(self.pushButton1_48_clicked)  # A Z移动开启按钮
        self.pushButton1_50.clicked.connect(self.pushButton1_50_clicked)  # A X移动开启按钮
        self.pushButton1_51.clicked.connect(self.pushButton1_51_clicked)  # A Y移动开启按钮
        self.pushButton1_56.clicked.connect(self.pushButton1_56_clicked)  # A R旋转开启按钮
        self.pushButton1_57.clicked.connect(self.pushButton1_57_clicked)  # A 转台旋转开启按钮

        self.pushButton1_39.clicked.connect(self.pushButton1_39_clicked)  # B 聚焦开启按钮，点一次开启，再点一次关闭
        self.pushButton1_43.clicked.connect(self.pushButton1_43_clicked)  # B 偏压开启按钮，点一次开启，再点一次关闭
        self.pushButton1_42.clicked.connect(self.pushButton1_42_clicked)  # B 灯丝开启按钮，点一次开启，再点一次关闭
        self.pushButton1_41.clicked.connect(self.pushButton1_41_clicked)  # B 高压开启按钮，点一次开启，再点一次关闭
        self.pushButton1_40.clicked.connect(self.pushButton1_40_clicked)  # B 束流开启按钮，点一次开启，再点一次关闭
        self.pushButton1_45.clicked.connect(self.pushButton1_45_clicked)  # B 移动开启按钮，点一次开启执行一轮移动，依次按输入信息增加
        self.pushButton1_49.clicked.connect(self.pushButton1_49_clicked)  # B Z移动开启按钮
        self.pushButton1_52.clicked.connect(self.pushButton1_52_clicked)  # B X移动开启按钮
        self.pushButton1_53.clicked.connect(self.pushButton1_53_clicked)  # B Y移动开启按钮
        self.pushButton1_54.clicked.connect(self.pushButton1_54_clicked)  # B R旋转开启按钮
        self.pushButton1_55.clicked.connect(self.pushButton1_55_clicked)  # B 转台旋转开启按钮

        # 多选框事件绑定
        self.checkBox_2.stateChanged.connect(self.update_status)
        self.checkBox_3.stateChanged.connect(self.update_status)
        self.checkBox_4.stateChanged.connect(self.update_status)
        self.checkBox_5.stateChanged.connect(self.update_status)
        self.checkBox_6.stateChanged.connect(self.update_status)
        self.checkBox_7.stateChanged.connect(self.update_status)
        self.checkBox_8.stateChanged.connect(self.update_status)
        self.checkBox_9.stateChanged.connect(self.update_status)
        self.checkBox_10.stateChanged.connect(self.update_status)
        self.checkBox_11.stateChanged.connect(self.update_status)
        self.checkBox_12.stateChanged.connect(self.update_status)
        self.checkBox_13.stateChanged.connect(self.update_status)
        self.checkBox_14.stateChanged.connect(self.update_status)
        self.checkBox_15.stateChanged.connect(self.update_status)
        self.checkBox_16.stateChanged.connect(self.update_status)
        self.checkBox_17.stateChanged.connect(self.update_status)
        self.checkBox_18.stateChanged.connect(self.update_status)
        self.checkBox_19.stateChanged.connect(self.update_status)

        self.checkBox_20.stateChanged.connect(self.time_update_status)     # 滚动图表
        self.radioButton.clicked.connect(self.clear_data_update_status)    # 定时清数据
        self.radioButton_2.clicked.connect(self.clear_data_update_status)  # 开门清数据
        self.radioButton_3.clicked.connect(self.Display_Range_update_status)  # 显示数据范围仅下束
        self.radioButton_4.clicked.connect(self.Display_Range_update_status)  # 显示数据范围全部
        self.radioButton_5.clicked.connect(self.Save_scope_update_status)     # 保存数据范围仅焊接
        self.radioButton_6.clicked.connect(self.Save_scope_update_status)     # 保存数据范围所有下束
        self.radioButton_7.clicked.connect(self.Save_scope_update_status)     # 保存数据范围全部数据

        # 标签页被点击
        self.tabWidget.tabBarClicked.connect(self.tab_clicked)  # tab页面切换标签被点击
        # 下拉框事件绑定
        self.comboBox_10.currentIndexChanged.connect(self.comboBox_10_change)  # 新建表下拉框内容发生改变时事件绑定
        # 临时测试按钮
        self.pushButton1_14.clicked.connect(self.pushButton1_14_clicked)  # 关门按钮
        self.pushButton1_20.clicked.connect(self.pushButton1_20_clicked)  # 抽真空按钮
        self.pushButton1_16.clicked.connect(self.pushButton1_16_clicked)  # A焊接按钮
        self.pushButton1_44.clicked.connect(self.pushButton1_44_clicked)  # B焊接按钮
        # 下拉框事件绑定
        # self.comboBox.currentIndexChanged.connect(self.comboBox_change)  # 下拉框索引选项改变时动作函数绑定

        # 滑动条事件绑定
        self.verticalSlider.valueChanged.connect(self.Slidervalue_Changed)
        # 枪转台旋转参数变化事件绑定

    # 预设数据初始化
    def preset_data_init(self):
        # 0窗口
        # 下拉框
        self.comboBox_2.addItem("A枪")
        self.comboBox_2.addItem("B枪")
        self.comboBox.addItem("坐标")
        self.comboBox.addItem("速度")
        self.comboBox_3.addItem("X", "0")
        self.comboBox_3.addItem("Y", "1")
        self.comboBox_3.addItem("Z", "2")
        self.comboBox_3.addItem("R", "3")
        self.comboBox_3.addItem("全部", "-1")
        # ----------------------- json 数据读取 ----------------------
        global newList_Template
        sqls = self.load_sqls()
        self.comboBox_10.clear()
        for sql in sqls:
            self.comboBox_10.addItem(sql["Variable"], sql["TableName"])
            if sql["Variable"] == "\u8fc7\u7a0b\u6570\u636e":
                self.lineEdit1_14.setText(sql["TableName"])  # 表名称初始化
                self.textEdit1.setText(sql["data"])  # 数据库新建表内容输入框
        # 1窗口初始化
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'  # 设置存储文件
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            key_v_data = json.load(file)
        self.lineEdit1_54.setText(str(key_v_data["3Dline"]["X_min"]))
        self.lineEdit1_55.setText(str(key_v_data["3Dline"]["X_max"]))
        self.lineEdit1_56.setText(str(key_v_data["3Dline"]["Y_min"]))
        self.lineEdit1_57.setText(str(key_v_data["3Dline"]["Y_max"]))
        self.lineEdit1_58.setText(str(key_v_data["3Dline"]["Z_min"]))
        self.lineEdit1_59.setText(str(key_v_data["3Dline"]["Z_max"]))
        self.lineEdit1_68.setText(str(key_v_data["3Dline"]["pi1#X"]))
        self.lineEdit1_69.setText(str(key_v_data["3Dline"]["pi1#Y"]))
        self.lineEdit1_70.setText(str(key_v_data["3Dline"]["pi2#X"]))
        self.lineEdit1_71.setText(str(key_v_data["3Dline"]["pi2#Y"]))
        self.lineEdit1_72.setText(str(key_v_data["other"]["Real_time_data_length"]))
        self.checkBox_20.setChecked(key_v_data["other"]["实时图像滚动"])       # 滚动图表
        self.radioButton.setChecked(key_v_data["other"]["定时清数据"])         # 定时清数据
        self.radioButton_2.setChecked(key_v_data["other"]["开门清数据"])       # 开门清数据
        self.radioButton_3.setChecked(key_v_data["other"]["仅下束"])          # 显示数据范围，仅下束
        self.radioButton_4.setChecked(key_v_data["other"]["全部"])            # 显示数据范围，全部
        self.radioButton_5.setChecked(key_v_data["other"]["仅焊接"])          # 保存数据范围，仅焊接
        self.radioButton_6.setChecked(key_v_data["other"]["所有下束"])        # 保存数据范围，所有下束
        self.radioButton_7.setChecked(key_v_data["other"]["全部数据"])        # 保存数据范围，全部数据

        # 3窗口初始化
        # A
        self.lineEdit1_26.setText(str(1000))   # X正向移动
        self.lineEdit1_27.setText(str(2000))   # Y正向移动
        self.lineEdit1_28.setText(str(-1000))  # X负向移动
        self.lineEdit1_29.setText(str(-2000))  # Y负向移动
        self.lineEdit1_30.setText(str(200))    # Z正向移动
        self.lineEdit1_61.setText(str(1000))   # X手动移动
        self.lineEdit1_63.setText(str(2000))   # Y手动移动
        # B
        self.lineEdit1_49.setText(str(1000))   # X正向移动
        self.lineEdit1_50.setText(str(2000))   # Y正向移动
        self.lineEdit1_51.setText(str(-1000))  # X负向移动
        self.lineEdit1_52.setText(str(-2000))  # Y负向移动
        self.lineEdit1_53.setText(str(200))    # Z正向移动
        self.lineEdit1_60.setText(str(1000))   # X手动移动
        self.lineEdit1_62.setText(str(2000))   # Y手动移动
        # 4窗口初始化
        self.checkBox_2.setText("聚焦(V)")
        self.checkBox_2.setStyleSheet(self.colors_mc[0])
        self.checkBox_3.setText("偏压(V)")
        self.checkBox_3.setStyleSheet(self.colors_mc[1])
        self.checkBox_4.setText("灯丝(A)")
        self.checkBox_4.setStyleSheet(self.colors_mc[2])
        self.checkBox_5.setText("高压(KV)")
        self.checkBox_5.setStyleSheet(self.colors_mc[3])
        self.checkBox_6.setText("束流(MA)")
        self.checkBox_6.setStyleSheet(self.colors_mc[4])
        self.checkBox_11.setText("扫描频率")
        self.checkBox_11.setStyleSheet(self.colors_mc[5])
        self.checkBox_12.setText("扫描X轴")
        self.checkBox_12.setStyleSheet(self.colors_mc[6])
        self.checkBox_13.setText("扫描Y轴")
        self.checkBox_13.setStyleSheet(self.colors_mc[7])
        self.checkBox_14.setText("偏转X轴")
        self.checkBox_14.setStyleSheet(self.colors_mc[8])
        self.checkBox_15.setText("偏转Y轴")
        self.checkBox_15.setStyleSheet(self.colors_mc[9])
        self.checkBox_16.setText("合轴X轴")
        self.checkBox_16.setStyleSheet(self.colors_mc[10])
        self.checkBox_17.setText("合轴Y轴")
        self.checkBox_17.setStyleSheet(self.colors_mc[11])
        self.checkBox_18.setText("像散X轴")
        self.checkBox_18.setStyleSheet(self.colors_mc[12])
        self.checkBox_19.setText("像散Y轴")
        self.checkBox_19.setStyleSheet(self.colors_mc[13])
        self.checkBox_7.setText("枪室真空度")
        self.checkBox_7.setStyleSheet(self.colors_mc[14])
        self.checkBox_8.setText("焊室真空度")
        self.checkBox_8.setStyleSheet(self.colors_mc[15])
        self.checkBox_9.setText("R角度")
        self.checkBox_9.setStyleSheet(self.colors_mc[16])
        self.checkBox_10.setText("转台角度")
        self.checkBox_10.setStyleSheet(self.colors_mc[17])
        self.label_8.setText("120分钟")
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/legend.json'
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            self.key_v_data = json.load(file)
        # 多选状态初始化
        self.checkBox_2.setChecked(self.key_v_data[self.checkBox_2.text()])
        self.checkBox_3.setChecked(self.key_v_data[self.checkBox_3.text()])
        self.checkBox_4.setChecked(self.key_v_data[self.checkBox_4.text()])
        self.checkBox_5.setChecked(self.key_v_data[self.checkBox_5.text()])
        self.checkBox_6.setChecked(self.key_v_data[self.checkBox_6.text()])
        self.checkBox_7.setChecked(self.key_v_data[self.checkBox_7.text()])
        self.checkBox_8.setChecked(self.key_v_data[self.checkBox_8.text()])
        self.checkBox_9.setChecked(self.key_v_data[self.checkBox_9.text()])
        self.checkBox_10.setChecked(self.key_v_data[self.checkBox_10.text()])
        self.checkBox_11.setChecked(self.key_v_data[self.checkBox_11.text()])
        self.checkBox_12.setChecked(self.key_v_data[self.checkBox_12.text()])
        self.checkBox_13.setChecked(self.key_v_data[self.checkBox_13.text()])
        self.checkBox_14.setChecked(self.key_v_data[self.checkBox_14.text()])
        self.checkBox_15.setChecked(self.key_v_data[self.checkBox_15.text()])
        self.checkBox_16.setChecked(self.key_v_data[self.checkBox_16.text()])
        self.checkBox_17.setChecked(self.key_v_data[self.checkBox_17.text()])
        self.checkBox_18.setChecked(self.key_v_data[self.checkBox_18.text()])
        self.checkBox_19.setChecked(self.key_v_data[self.checkBox_19.text()])

    # 2D A枪状态初始化
    def update_R_time_data_ini_A(self):
        # 计算当前时间减去两小时
        two_hours_ago = datetime.now() - timedelta(hours=2)
        # 将时间转换为字符串格式 (注意：SQL Server 的日期时间格式通常为 'yyyy-mm-dd HH:MM:SS')
        time_str = two_hours_ago.strftime('%Y-%m-%d %H:%M:%S')

        # A表初始化显示
        self.cursor.execute(
            "SELECT 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
            "枪室真空度,焊室真空度,R角度,转台角度,X坐标,Y坐标,Z坐标 FROM persons_A WHERE 日期时间 >= %s", time_str)
        # 获取查询结果（返回最后一行数据）
        data1 = self.cursor.fetchall()
        data1 = list(data1)  # 转换为列表
        self.big_arr_a = len(data1)    # 存储从数据库中读取的数据大小
        if data1:
            for i, date in enumerate(data1):
                date_list = list(date)  # 将元组转换为列表
                date_list[0] = QDateTime(date_list[0].date(), date_list[0].time())  # 转换日期时间
                data1[i] = date_list  # 再将列表转换回元组，存回 data1
            data1 = np.array(data1)
            data_x = data1[:, 0]  # X轴的数据
            data_y = data1[:, 1:19]  # Y轴的数据
            data_y = data_y.transpose()  # 行列转换
            data_y = data_y.astype(float)
            data_xyz = data1[:, 19:22]
            self.min_y_A = np.min(data_y)  # 最小Y值
            self.max_y_A = np.max(data_y)  # 最大Y值
            data_x = data_x.tolist()
            data_y = data_y.tolist()
        else:
            data_x = [QDateTime.currentDateTime().addSecs(-self.fanwei),
                      QDateTime.currentDateTime().addSecs(-self.fanwei)]  # 获取当前的日期时间
            data_y = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
                      [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
            data_xyz = [[0, 0, 0], [0, 0, 0]]
            # print("No data found.")

        timestamp = []
        # 将 np_dates 转换为 QPointF 对象并添加到系列
        for i, x in enumerate(data_x):
            timestamp.append(x.toMSecsSinceEpoch())
        self.chart_line_A.clear()
        for i, data_y1 in enumerate(data_y):
            # print("data_y", data_y)
            self.chart_line_A.append(QLineSeries())
            # print("self.indexed_items", self.indexed_items)
            if self.indexed_items[i][1] == True:  # 判断多选
                # 使用 get() 方法确保键存在，避免抛出 KeyError
                # print("indexed_items", self.indexed_items[i][0])
                if self.indexed_items[i][0] not in self.shuju_zidian_A:
                    self.shuju_zidian_A[self.indexed_items[i][0]] = {}  # 如果没有该键，先创建一个空字典
                # 然后再进行赋值
                self.shuju_zidian_A[self.indexed_items[i][0]], self.chart_line_A[i], self.pen_style_A[i] = quxianluru(
                    data_x, data_y1, self.line_chart_A, self.axis_x_A, self.axis_y_A, self.colors[i],
                    self.pen_style_A[i])  # 录入一条曲线并设置名称

        self.axis_x_A.setRange(QDateTime.currentDateTime().addSecs(-self.fanwei),
                               QDateTime.currentDateTime())  # 设置轴的范围为 QDateTime 对象
        self.axis_y_A.setRange(self.min_y_A - 10, self.max_y_A + 10)
        self.old_time_A = data_x[-1]  # 读取数据库类型时，上一次时间存储
        for i, date_cnt_A in enumerate(data_xyz):     # 更新3维数据
            # print("date_cnt_A",date_cnt_A)
            self.time_xyz_A = np.append(self.time_xyz_A,
                                        [[timestamp[i], date_cnt_A[0], date_cnt_A[2], date_cnt_A[1]]],
                                        axis=0)
            self.data_3D_A.append(QScatterDataItem(QVector3D(date_cnt_A[0], date_cnt_A[2], date_cnt_A[1])))
        # 3D点位更新
        self.series_A.dataProxy().resetArray(self.data_3D_A)  # 修改这里，直接传递data列表
        return self.old_time_A.toMSecsSinceEpoch()  # 返回时间戳

    # 2D B枪状态初始化
    def update_R_time_data_ini_B(self):
        # 计算当前时间减去两小时
        two_hours_ago = datetime.now() - timedelta(hours=2)
        # 将时间转换为字符串格式 (注意：SQL Server 的日期时间格式通常为 'yyyy-mm-dd HH:MM:SS')
        time_str = two_hours_ago.strftime('%Y-%m-%d %H:%M:%S')
        # print("time_str", time_str)
        # B表初始化显示
        self.cursor.execute(
            "SELECT 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
            "枪室真空度,焊室真空度,R角度,转台角度,X坐标,Y坐标,Z坐标 FROM persons_B WHERE 日期时间 >= %s", time_str)
        # 获取查询结果（返回最后一行数据）
        data2 = self.cursor.fetchall()
        data2 = list(data2)  # 转换为列表
        self.big_arr_b = len(data2)  # 存储从数据库中读取的数据大小
        if data2:
            for i, date in enumerate(data2):
                date_list = list(date)  # 将元组转换为列表
                date_list[0] = QDateTime(date_list[0].date(), date_list[0].time())  # 转换日期时间
                data2[i] = date_list  # 再将列表转换回元组，存回 data2
            data2 = np.array(data2)
            data_x_B = data2[:, 0]  # X轴的数据
            data_y = data2[:, 1:19]  # Y轴的数据
            data_y = data_y.transpose()  # 行列转换
            data_y = data_y.astype(float)
            data_xyz = data2[:, 19:22]
            self.min_y_B = np.min(data_y)  # 最小Y值
            self.max_y_B = np.max(data_y)  # 最大Y值
            data_x_B = data_x_B.tolist()
            data_y = data_y.tolist()
            # print("data_y",data_y)
        else:
            data_x_B = [QDateTime.currentDateTime().addSecs(-self.fanwei),
                        QDateTime.currentDateTime().addSecs(-self.fanwei)]  # 获取当前的日期时间
            data_y = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
                      [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
            data_xyz = [[0,0,0],[0,0,0]]

        timestamp = []
        # 将 np_dates 转换为 QPointF 对象并添加到系列
        for i, x in enumerate(data_x_B):
            timestamp.append(x.toMSecsSinceEpoch())
        self.chart_line_B.clear()
        for i, data_y1 in enumerate(data_y):
            self.chart_line_B.append(QLineSeries())
            if self.indexed_items[i][1] == True:  # 判断多选
                # 使用 get() 方法确保键存在，避免抛出 KeyError
                if self.indexed_items[i][0] not in self.shuju_zidian_B:
                    self.shuju_zidian_B[self.indexed_items[i][0]] = {}  # 如果没有该键，先创建一个空字典
                # 然后再进行赋值
                self.shuju_zidian_B[self.indexed_items[i][0]], self.chart_line_B[i], self.pen_style_B[i] = quxianluru(
                    data_x_B, data_y1, self.line_chart_B, self.axis_x_B, self.axis_y_B, self.colors[i],
                    self.pen_style_B[i])  # 录入一条曲线并设置名称

        self.axis_x_B.setRange(QDateTime.currentDateTime().addSecs(-self.fanwei),
                               QDateTime.currentDateTime())  # 设置轴的范围为 QDateTime 对象
        self.axis_y_B.setRange(self.min_y_B - 10, self.max_y_B + 10)
        self.old_time_B = data_x_B[-1]  # 读取数据库类型时，上一次时间存储
        for i, date_cnt_B in enumerate(data_xyz):     # 更新3维数据
            # print("date_cnt_B",date_cnt_B)
            self.time_xyz_B = np.append(self.time_xyz_B,
                                        [[timestamp[i], date_cnt_B[0], date_cnt_B[2], date_cnt_B[1]]],
                                        axis=0)
            self.data_3D_B.append(QScatterDataItem(QVector3D(date_cnt_B[0], date_cnt_B[2], date_cnt_B[1])))
        # 3D点位更新
        self.series_B.dataProxy().resetArray(self.data_3D_B)  # 修改这里，直接传递data列表
        return self.old_time_B.toMSecsSinceEpoch()

    # 2D A枪数据刷新
    def dele_time_data_ini_A(self):
        # 计算当前时间减去两小时
        # two_hours_ago = datetime.now() - timedelta(hours=2)
        # # 将时间转换为字符串格式 (注意：SQL Server 的日期时间格式通常为 'yyyy-mm-dd HH:MM:SS')
        # time_str = two_hours_ago.strftime('%Y-%m-%d %H:%M:%S')
        # print("time_str", time_str)
        json_file = 'H_S_JSON/System_settings.json'  # 设置存储文件
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            key_v_data = json.load(file)
        # B表初始化显示
        self.cursor.execute(
            "SELECT TOP %s 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
            "枪室真空度,焊室真空度,R角度,转台角度 FROM persons_A", (key_v_data["other"]["Real_time_data_length"],))
        # 获取查询结果（返回最后一行数据）
        data2 = self.cursor.fetchall()
        data2 = list(data2)  # 转换为列表
        self.big_arr_b = len(data2)  # 存储从数据库中读取的数据大小
        if data2:
            for i, date in enumerate(data2):
                date_list = list(date)  # 将元组转换为列表
                date_list[0] = QDateTime(date_list[0].date(), date_list[0].time())  # 转换日期时间
                data2[i] = date_list  # 再将列表转换回元组，存回 data2
            data2 = np.array(data2)
            data_x_A = data2[:, 0]  # X轴的数据
            data_y = data2[:, 1:]  # Y轴的数据
            data_y = data_y.transpose()  # 行列转换
            data_y = data_y.astype(float)
            self.min_y_A = np.min(data_y)  # 最小Y值
            self.max_y_A = np.max(data_y)  # 最大Y值
            data_x_A = data_x_A.tolist()
            data_y = data_y.tolist()
        else:
            data_x_A = [QDateTime.currentDateTime().addSecs(-self.fanwei),
                        QDateTime.currentDateTime().addSecs(-self.fanwei)]  # 获取当前的日期时间
            data_y = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
                      [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
            # print("No data found.")

        timestamp = []
        # 将 np_dates 转换为 QPointF 对象并添加到系列
        for i, x in enumerate(data_x_A):
            timestamp.append(x.toMSecsSinceEpoch())
        self.chart_line_A.clear()
        for i, data_y1 in enumerate(data_y):
            self.chart_line_A.append(QLineSeries())
            if self.indexed_items[i][1] == True:  # 判断多选
                # 使用 get() 方法确保键存在，避免抛出 KeyError
                if self.indexed_items[i][0] not in self.shuju_zidian_A:
                    self.shuju_zidian_A[self.indexed_items[i][0]] = {}  # 如果没有该键，先创建一个空字典
                # 然后再进行赋值
                self.shuju_zidian_A[self.indexed_items[i][0]], self.chart_line_B[i], self.pen_style_A[i] = quxianluru(
                    data_x_A, data_y1, self.line_chart_A, self.axis_x_A, self.axis_y_A, self.colors[i],
                    self.pen_style_A[i])  # 录入一条曲线并设置名称

        self.axis_x_A.setRange(QDateTime.currentDateTime().addSecs(-self.fanwei),
                               QDateTime.currentDateTime())  # 设置轴的范围为 QDateTime 对象
        self.axis_y_A.setRange(self.min_y_A - 10, self.max_y_A + 10)

        self.old_time_A = data_x_A[-1]  # 读取数据库类型时，上一次时间存储
        return self.old_time_A.toMSecsSinceEpoch()

    # 2D B枪数据刷新
    def dele_time_data_ini_B(self):
        # 计算当前时间减去两小时
        # two_hours_ago = datetime.now() - timedelta(hours=2)
        # # 将时间转换为字符串格式 (注意：SQL Server 的日期时间格式通常为 'yyyy-mm-dd HH:MM:SS')
        # time_str = two_hours_ago.strftime('%Y-%m-%d %H:%M:%S')
        # print("time_str", time_str)
        json_file = 'H_S_JSON/System_settings.json'  # 设置存储文件
        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            key_v_data = json.load(file)
        # B表初始化显示
        self.cursor.execute(
            "SELECT TOP %s 日期时间,[聚焦显示(V)],[偏压显示(V)],[灯丝显示(A)],[高压显示(KV)],[束流显示(MA)],"
            "扫描频率, 扫描X轴, 扫描Y轴, 偏转X轴, 偏转Y轴, 合轴X轴, 合轴Y轴, 像散X轴, 像散Y轴, "
            "枪室真空度,焊室真空度,R角度,转台角度 FROM persons_B", (key_v_data["other"]["Real_time_data_length"],))
        # 获取查询结果（返回最后一行数据）
        data2 = self.cursor.fetchall()
        data2 = list(data2)  # 转换为列表
        self.big_arr_b = len(data2)  # 存储从数据库中读取的数据大小
        if data2:
            for i, date in enumerate(data2):
                date_list = list(date)  # 将元组转换为列表
                date_list[0] = QDateTime(date_list[0].date(), date_list[0].time())  # 转换日期时间
                data2[i] = date_list  # 再将列表转换回元组，存回 data2
            data2 = np.array(data2)
            data_x_B = data2[:, 0]  # X轴的数据
            data_y = data2[:, 1:]  # Y轴的数据
            data_y = data_y.transpose()  # 行列转换
            data_y = data_y.astype(float)
            self.min_y_B = np.min(data_y)  # 最小Y值
            self.max_y_B = np.max(data_y)  # 最大Y值
            data_x_B = data_x_B.tolist()
            data_y = data_y.tolist()
        else:
            data_x_B = [QDateTime.currentDateTime().addSecs(-self.fanwei),
                        QDateTime.currentDateTime().addSecs(-self.fanwei)]  # 获取当前的日期时间
            data_y = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0],
                      [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
            # print("No data found.")

        timestamp = []
        # 将 np_dates 转换为 QPointF 对象并添加到系列
        for i, x in enumerate(data_x_B):
            timestamp.append(x.toMSecsSinceEpoch())
        self.chart_line_B.clear()
        for i, data_y1 in enumerate(data_y):
            self.chart_line_B.append(QLineSeries())
            if self.indexed_items[i][1] == True:  # 判断多选
                # 使用 get() 方法确保键存在，避免抛出 KeyError
                if self.indexed_items[i][0] not in self.shuju_zidian_B:
                    self.shuju_zidian_B[self.indexed_items[i][0]] = {}  # 如果没有该键，先创建一个空字典
                # 然后再进行赋值
                self.shuju_zidian_B[self.indexed_items[i][0]], self.chart_line_B[i], self.pen_style_B[i] = quxianluru(
                    data_x_B, data_y1, self.line_chart_B, self.axis_x_B, self.axis_y_B, self.colors[i],
                    self.pen_style_B[i])  # 录入一条曲线并设置名称

        self.axis_x_B.setRange(QDateTime.currentDateTime().addSecs(-self.fanwei),
                               QDateTime.currentDateTime())  # 设置轴的范围为 QDateTime 对象
        self.axis_y_B.setRange(self.min_y_B - 10, self.max_y_B + 10)

        self.old_time_B = data_x_B[-1]  # 读取数据库类型时，上一次时间存储
        return self.old_time_B.toMSecsSinceEpoch()


    # ----------------标签页切换页面更新--------------------
    def tab_clicked(self, index):  # tab_4修改与删除页面切换标签被点击
        # 链接与调试,数据库调试页面
        if index == 0:
            # 输入框
            self.lineEdit1.setText(url)
            self.lineEdit1_2.setText(opc_username)
            self.lineEdit1_3.setText(opc_password)
            self.lineEdit1_5.setText(ipA)
            self.lineEdit1_6.setText(str(portA))
            self.lineEdit1_8.setText(ipB)
            self.lineEdit1_7.setText(str(portB))

            # 输入框
            self.lineEdit1_9.setText(servermy)
            self.lineEdit1_10.setText(portmy)
            self.lineEdit1_11.setText(usermy)
            self.lineEdit1_4.setText(passwordmy)
            self.lineEdit1_12.setText(databasemy)
            self.lineEdit1_13.setText(newdatabasemy)

        # 系统设置页面
        # if index == 1: #System settings

        # 数据库查询页面
        if index == 2:
            self.comboBox_4.clear()
            self.comboBox_5.clear()
            self.comboBox_6.clear()
            self.comboBox_7.clear()
            self.comboBox_8.clear()
            self.comboBox_9.clear()
            self.comboBox_11.clear()
            self.cursor.execute(
                """SELECT
                    坯组编号,
                    操作员
                FROM
                    production""")
            results = self.cursor.fetchall()  # 获取查询到的所有信息
            results_zh = np.transpose(results)  # np.transpose行列转换
            unique_pizu = np.unique(results_zh[0])  # 坯组编号去重计算
            # print(unique_pizu)
            unique_caozuo = np.unique(results_zh[1])  # 操作员去重计算
            self.comboBox_6.addItem(None)
            self.comboBox_4.addItem(None)
            for i in unique_pizu:
                self.comboBox_6.addItem(i)
                self.comboBox_4.addItem(i)
            self.comboBox_9.addItem(None)
            self.comboBox_5.addItem(None)
            for i in unique_caozuo:
                self.comboBox_9.addItem(str(i.encode('latin1').decode('gbk')))
                self.comboBox_5.addItem(str(i.encode('latin1').decode('gbk')))
            self.comboBox_11.addItem(None)
            for i in range(1, 9):
                self.comboBox_11.addItem(str(i))
            self.cursor.execute(
                """SELECT
                    板坯编号,
                    原料材质
                FROM
                    material""")
            results = self.cursor.fetchall()  # 获取查询到的所有信息
            results_zh = np.transpose(results)  # np.transpose行列转换
            unique_banpi = np.unique(results_zh[0])  # 板坯编号去重计算
            unique_caizhi = np.unique(results_zh[1])  #
            self.comboBox_7.addItem(None)
            for i in unique_banpi:
                self.comboBox_7.addItem(i)
            self.comboBox_8.addItem(None)
            for i in unique_caizhi:
                self.comboBox_8.addItem(i)
            # 获取当前的日期时间
            current_date_time = QDateTime.currentDateTime()
            # 将 QDateTimeEdit 设置为当前日期时间
            self.dateTimeEdit.setDateTime(current_date_time.addDays(-1))
            self.dateTimeEdit_3.setDateTime(current_date_time.addDays(-1))
            self.dateTimeEdit_4.setDateTime(current_date_time)
            self.dateTimeEdit_2.setDateTime(current_date_time)

        # 采集页面初始化
        if index == 3:
            # A
            self.lineEdit1_21.setText(str(round(uniform(299, 301), 1)))  # 聚焦
            self.lineEdit1_22.setText(str(round(uniform(2400, 2600), 1)))  # 偏压
            self.lineEdit1_23.setText(str(round(uniform(45, 48), 1)))  # 灯丝
            self.lineEdit1_24.setText(str(round(uniform(59, 61), 1)))  # 高压
            self.lineEdit1_25.setText(str(round(uniform(100, 180), 1)))  # 束流
            # B
            self.lineEdit1_36.setText(str(round(uniform(299, 301), 1)))  # 聚焦
            self.lineEdit1_37.setText(str(round(uniform(2400, 2600), 1)))  # 偏压
            self.lineEdit1_39.setText(str(round(uniform(45, 48), 1)))  # 灯丝
            self.lineEdit1_38.setText(str(round(uniform(59, 61), 1)))  # 高压
            self.lineEdit1_35.setText(str(round(uniform(100, 180), 1)))  # 束流

            # A
            self.lineEdit1_31.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_32.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_33.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_34.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_65.setText(str(round(uniform(89, 91), 1)))  # R手动旋转
            self.lineEdit1_67.setText(str(round(uniform(89, 91), 1)))  # 转台手动旋转
            # B
            self.lineEdit1_45.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_46.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_47.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_48.setText(str(round(uniform(89, 91), 1)))  # R旋转
            self.lineEdit1_64.setText(str(round(uniform(89, 91), 1)))  # R手动旋转
            self.lineEdit1_66.setText(str(round(uniform(89, 91), 1)))  # 转台手动旋转

        # 实时数据页面
        if index == 4:
            # 指定要操作的JSON文件名
            json_file = 'H_S_JSON/legend.json'
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                self.key_v_data = json.load(file)
            # 多选状态初始化
            self.checkBox_2.setChecked(self.key_v_data[self.checkBox_2.text()])
            self.checkBox_3.setChecked(self.key_v_data[self.checkBox_3.text()])
            self.checkBox_4.setChecked(self.key_v_data[self.checkBox_4.text()])
            self.checkBox_5.setChecked(self.key_v_data[self.checkBox_5.text()])
            self.checkBox_6.setChecked(self.key_v_data[self.checkBox_6.text()])
            self.checkBox_7.setChecked(self.key_v_data[self.checkBox_7.text()])
            self.checkBox_8.setChecked(self.key_v_data[self.checkBox_8.text()])
            self.checkBox_9.setChecked(self.key_v_data[self.checkBox_9.text()])
            self.checkBox_10.setChecked(self.key_v_data[self.checkBox_10.text()])
            self.checkBox_11.setChecked(self.key_v_data[self.checkBox_11.text()])
            self.checkBox_12.setChecked(self.key_v_data[self.checkBox_12.text()])
            self.checkBox_13.setChecked(self.key_v_data[self.checkBox_13.text()])
            self.checkBox_14.setChecked(self.key_v_data[self.checkBox_14.text()])
            self.checkBox_15.setChecked(self.key_v_data[self.checkBox_15.text()])
            self.checkBox_16.setChecked(self.key_v_data[self.checkBox_16.text()])
            self.checkBox_17.setChecked(self.key_v_data[self.checkBox_17.text()])
            self.checkBox_18.setChecked(self.key_v_data[self.checkBox_18.text()])
            self.checkBox_19.setChecked(self.key_v_data[self.checkBox_19.text()])

        # 未定义数据查询页面
        if index == 5:
            self.comboBox_12.clear()  # 临时数据下拉框
            self.cursor.execute(
                """SELECT
                    坯组编号
                FROM
                    persons
                WHERE 坯组编号 LIKE N'%无分配%'
                    """)
            results = self.cursor.fetchall()  # 获取查询到的所有信息
            results_zh = np.transpose(results)  # np.transpose行列转换
            unique_pizu = np.unique(results_zh)  # 坯组编号去重计算
            # print(unique_pizu)

            self.comboBox_12.addItem(None)
            for i in unique_pizu:
                self.comboBox_12.addItem(str(i.encode('latin1').decode('gbk')))

            # 获取当前的日期时间
            current_date_time = QDateTime.currentDateTime()
            # 将 QDateTimeEdit 设置为当前日期时间
            self.dateTimeEdit_5.setDateTime(current_date_time.addDays(-1))
            self.dateTimeEdit_6.setDateTime(current_date_time)

    # -------------------窗口事件--------------------
    def focusInEvent(self, event):  # 窗口获得焦点事件
        self.label_54.setText(username_main)
        self.label_56.setText(permissions_main)
        super().focusInEvent(event)

    # -------------------外部方法--------------------
    # 表格合并同类项程序
    def hebing(self, tablewg):
        types = {}  #合并同类型单元格
        for row in range(tablewg.rowCount()):
            type_item = tablewg.item(row, 0)
            if type_item is not None:
                type_text = type_item.text()
                if type_text not in types:
                    types[type_text] = []
                types[type_text].append(row)
        # print(types)
        for type_text, rows in types.items():
            if len(rows) > 1:
                start_row = rows[0]
                row_span = len(rows)
                tablewg.setSpan(start_row, 0, row_span, 1)

    # --------------------json操作事件------------------
    def load_sqls(self):  # 读取账号文件信息
        with open(self.USER_DATA_FILE, 'r', encoding='utf-8') as file:
            data = json.load(file)
        return data['sql']

    def save_sqls(self, sqls):  # 存储用户
        with open(self.USER_DATA_FILE, 'w', encoding='utf-8') as file:
            json.dump({"sql": sqls}, file, indent=4)

    # 3D图像散点被点击事件
    def on_scatter_point_clicked(self, series):
        self.series_chocked = series
        if series == self.series_A:
            selected_point_index = series.selectedItem()
            point = series.dataProxy().itemAt(selected_point_index)
            x = point.x()
            y = point.y()
            z = point.z()
            # print(f"A点击的坐标为：", self.time_xyz_A)
            for v in self.time_xyz_A:
                print(v[1:3])
                if v[1] == x and v[2] == y and v[3] == z:
                    self.chart_view_A.show_yun(v[0])
                    # print(f"A点击的时间为：({k})")

        elif series == self.series_B:
            selected_point_index = series.selectedItem()
            point = series.dataProxy().itemAt(selected_point_index)
            x = point.x()
            y = point.y()
            z = point.z()
            # print(f"B点击的坐标为：({x}，{y}，{z})")
            for v in self.time_xyz_B:
                if v[1] == x and v[2] == y and v[3] == z:
                    self.chart_view_B.show_yun(v[0])
                    # print(f"B点击的时间为：({k})")

    # 3D图像点击空白处事件
    def handle_viewport_click(self):
        # 当点击空白区域时主动清除选中状态
        # print("self.series_chocked", self.series_chocked)
        # print("self.series_chock_old", self.series_chock_old)
        if self.series_chocked == self.series_chock_old:
            self.series_chock_old = None
            self.chart_view_A.close_yun()
            self.chart_view_B.close_yun()
            print("点中空白处")
        elif self.series_chocked != None and self.series_chock_old == None:
            print("点中异点处")
            self.series_chock_old = self.series_chocked
        elif self.series_chocked != self.series_chock_old:
            print("点中异点处")
            self.series_chock_old = self.series_chocked
        elif self.series_chocked == None and self.series_chock_old != None:
            self.series_chock_old = None
            self.chart_view_A.close_yun()
            self.chart_view_B.close_yun()
            print("点中空白处")

    # ---------------------定时器任务-------------------
    @Slot(object)
    def showtime2_A(self, data1):  # A实时数据图像更新
        # start_time = times.time()
        self.data_xyz_A.clear()
        self.big_arr_a = self.big_arr_a + len(data1)  # 增加实时数据已存储数据
        # A枪数据更新
        for data in data1:
            timestamp = data[0].toMSecsSinceEpoch()  #时间日期的时间戳
            data_y = data[1:19]  # Y轴的数据
            date_cnt = data[19:22]  # 枪坐标的数据
            data_y = np.array(data_y)  # 转化为np数组
            min_y = np.min(data_y)  # 最小Y值
            max_y = np.max(data_y)  # 最大Y值

            self.min_y_A, self.max_y_A = range_exceeds(min_y, max_y, self.min_y_A, self.max_y_A, self.axis_y_A)  # 判断是否超限并更新范围 A枪
            data_y = data_y.tolist()  # 转化为列表
            # 多选状态
            for i, view in enumerate(self.chart_line_A):  # 曲线对象集合
                if self.indexed_items[i][1]:  # 判断多选
                    if abs(data[0].secsTo(self.old_time_A)) > 4:
                        print("A大于4秒")
                        # print("self.pen_style_A[i]",self.pen_style_A[i])
                        if self.pen_style_A[i]:
                            # print("A改变画笔为虚线")
                            self.chart_line_A[i] = server(self.line_chart_A, self.axis_x_A, self.axis_y_A,
                                                          Qt.black, Qt.DotLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                            self.pen_style_A[i] = 0  # 曲线笔模式状态，1：实线，0：虚线
                    else:
                        if not self.pen_style_A[i]:
                            # print("A改变画笔为实线")
                            self.chart_line_A[i] = server(self.line_chart_A, self.axis_x_A, self.axis_y_A,
                                                          self.colors[i], Qt.SolidLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                            self.pen_style_A[i] = 1  # 曲线笔模式状态，1：实线，0：曲线
                    self.chart_line_A[i].append(QPointF(timestamp, data_y[i]))  # 使用 QPointF 来表示 (时间戳, 数据点)
                    if self.radioButton.isChecked() and self.chart_line_A[i].count() > int(self.lineEdit1_72.text()):  # 删除旧点
                        self.chart_line_A[i].remove(0)
                    self.shuju_zidian_A[self.indexed_items[i][0]][timestamp] = data_y[i]  # 将数据存入字典中，以便在云框显示中获取
                    self.chart_view_A.shuju_zidian = self.shuju_zidian_A  # 更新数据到图框对象中

            self.time_xyz_A = np.append(self.time_xyz_A, [[timestamp, date_cnt[0], date_cnt[2], date_cnt[1]]], axis=0)
            self.data_3D_A.append(QScatterDataItem(QVector3D(date_cnt[0], date_cnt[2], date_cnt[1])))  # 更新3D点
            if self.radioButton.isChecked():
                if len(self.time_xyz_A) > int(self.lineEdit1_72.text()):  # 删除旧点
                    self.time_xyz_A = np.delete(self.time_xyz_A, 0, axis=0)
                if len(self.data_3D_A) > int(self.lineEdit1_72.text()):  # 删除旧点
                    self.data_3D_A.pop(0)
            # 跟随枪头运动，不跟数据库数据运动
            self.data_nowp_A.append(
                QScatterDataItem(
                    QVector3D(self.worker.Gun_p_A.X_l, self.worker.Gun_p_A.Z_l, self.worker.Gun_p_A.Y_l)))  # 更新当前点
            if len(self.data_nowp_A) > 2:  # 控制轨迹长度
                del self.data_nowp_A[0]  # 删除旧点 <- 关键修正点

            self.old_time_A = data[0]           # 读取数据库类型时，上一次时间存储
            self.worker.old_A.emit(data[0])     # 多线程旧时间同步
        # 3D点位更新
        self.nowp_A.dataProxy().resetArray(self.data_nowp_A)  # 修改这里，直接传递data列表
        self.series_A.dataProxy().resetArray(self.data_3D_A)  # 修改这里，直接传递data列表
        # 更新多线程中的坐标数组 t_xyz_A
        self.worker.t_xyz_A.emit(self.time_xyz_A)  # 多线程坐标数组同步
        # print(f"A图像更新 执行耗时:{times.time()-start_time:.6f}秒")  # 输出方法耗时

    @Slot(object)
    def showtime2_B(self, data1):  # B实时数据图像更新
        # start_time = times.time()
        self.data_xyz_B.clear()
        self.big_arr_b = self.big_arr_b + len(data1)   # 增加实时数据已存储数据
        # B枪数据更新
        for data in data1:
            timestamp = data[0].toMSecsSinceEpoch()
            data_y = data[1:19]  # Y轴的数据
            data_y = np.array(data_y)  # 转化为np数组
            date_cnt_B = data[19:22]  # 枪坐标的数据
            min_y = np.min(data_y)  # 最小Y值
            max_y = np.max(data_y)  # 最大Y值

            self.min_y_B, self.max_y_B = range_exceeds(min_y, max_y, self.min_y_B, self.max_y_B,self.axis_y_B)  # 判断是否超限并更新范围 B枪
            data_y = data_y.tolist()  # 转化为列表
            # 多选状态
            for i, view in enumerate(self.chart_line_B):  # 曲线对象集合
                if self.indexed_items[i][1]:  # 判断多选
                    if abs(data[0].secsTo(self.old_time_B)) > 4:
                        print("B大于4秒")
                        # print("self.pen_style_B[i]",self.pen_style_B[i])
                        if self.pen_style_B[i]:
                            # print("B改变画笔为虚线")
                            self.chart_line_B[i] = server(self.line_chart_B, self.axis_x_B, self.axis_y_B,
                                                          Qt.black,
                                                          Qt.DotLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                            self.pen_style_B[i] = 0  # 曲线笔模式状态，1：实线，0：曲线
                    else:
                        if not self.pen_style_B[i]:
                            # print("B改变画笔为实线")
                            self.chart_line_B[i] = server(self.line_chart_B, self.axis_x_B, self.axis_y_B,
                                                          self.colors[i],
                                                          Qt.SolidLine)  # chart对象 pen对象 X轴对象 Y轴对象 颜色 笔模式
                            self.pen_style_B[i] = 1  # 曲线笔模式状态，1：实线，0：曲线
                    self.chart_line_B[i].append(QPointF(timestamp, data_y[i]))  # 使用 QPointF 来表示 (时间戳, 数据点)
                    if self.radioButton.isChecked() and self.chart_line_B[i].count() > int(self.lineEdit1_72.text()):  # 删除旧点
                        self.chart_line_B[i].remove(0)
                    self.shuju_zidian_B[self.indexed_items[i][0]][timestamp] = data_y[i]  # 将数据存入字典中，以便在云框显示中获取
                    self.chart_view_B.shuju_zidian = self.shuju_zidian_B  # 更新数据到图框对象中

            self.time_xyz_B = np.append(self.time_xyz_B,
                                        [[timestamp, date_cnt_B[0], date_cnt_B[2], date_cnt_B[1]]],
                                        axis=0)
            self.data_3D_B.append(QScatterDataItem(QVector3D(date_cnt_B[0], date_cnt_B[2], date_cnt_B[1])))
            if self.radioButton.isChecked():
                if len(self.time_xyz_B) > int(self.lineEdit1_72.text()):  # 删除旧点
                    self.time_xyz_B = np.delete(self.time_xyz_B, 0, axis=0)
                if len(self.data_3D_B) > int(self.lineEdit1_72.text()):  # 删除旧点
                    self.data_3D_B.pop(0)
            self.data_nowp_B.append(
                QScatterDataItem(
                    QVector3D(self.worker.Gun_p_B.X_l, self.worker.Gun_p_B.Z_l,
                              self.worker.Gun_p_B.Y_l)))  # 跟随枪头运动，不跟数据库数据运动
            if len(self.data_nowp_B) > 2:  # 控制轨迹长度
                del self.data_nowp_B[0]  # 删除旧点 <- 关键修正点

            if self.chart_view_B.closest_key is not None:  # 更新鼠标点处3D数据
                if self.chart_view_B.time_key < self.chart_view_B.closest_key:
                    mask = (self.time_xyz_B[:, 0] == self.chart_view_B.closest_key)  # 生成布尔掩码
                    matched_rows = list(self.time_xyz_B[mask, :][0])  # 筛选符合条件的行‌
                    self.data_xyz_B.append(
                        QScatterDataItem(QVector3D(matched_rows[1], matched_rows[2], matched_rows[3])))
                    self.zhishi_c.dataProxy().resetArray(self.data_xyz_B)  # 修改这里，直接传递data列表
            elif self.chart_view_A.closest_key is not None:
                if self.chart_view_A.time_key < self.chart_view_A.closest_key:
                    mask = (self.time_xyz_A[:, 0] == self.chart_view_A.closest_key)  # 生成布尔掩码
                    matched_rows = list(self.time_xyz_A[mask, :][0])  # 筛选符合条件的行‌
                    self.data_xyz_B.append(
                        QScatterDataItem(QVector3D(matched_rows[1], matched_rows[2], matched_rows[3])))
                    self.zhishi_c.dataProxy().resetArray(self.data_xyz_B)  # 修改这里，直接传递data列表
            else:
                self.zhishi_c.dataProxy().resetArray([])  # 修改这里，直接传递data列表
            self.old_time_B = data[0]  # 读取数据库类型时，上一次时间存储
            self.worker.old_B.emit(data[0])  # 同步多线程数据，上一次时间存储
        # 动态滚动图表 QChart 对象
        # self.axis_x_B.setMin(QDateTime.currentDateTime().addSecs(-self.fanwei))
        # self.axis_x_B.setMax(QDateTime.currentDateTime())
        # 3D点位更新
        self.nowp_B.dataProxy().resetArray(self.data_nowp_B)  # 修改这里，直接传递data列表
        self.series_B.dataProxy().resetArray(self.data_3D_B)  # 修改这里，直接传递data列表
        # 更新多线程中的坐标数组 t_xyz_B
        self.worker.t_xyz_B.emit(self.time_xyz_B)  # 多线程坐标数组同步
        # print(f"B图像更新 执行耗时: {times.time() - start_time:.6f}秒")  # 输出方法耗时

    @Slot(object)
    def showtime3_A(self, data1):  # A旋转图像更新
        self.time_xyz_A = data1
        # 直接使用内存视图加速
        self.data_3D_A.clear()
        self.data_3D_A = [None] * len(self.time_xyz_A)

        for i in range(len(self.time_xyz_A)):
            self.data_3D_A[i] = QScatterDataItem(QVector3D(
                self.time_xyz_A[i, 1],
                self.time_xyz_A[i, 2],
                self.time_xyz_A[i, 3]
            ))
        self.series_A.dataProxy().resetArray(self.data_3D_A)

    @Slot(object)
    def showtime3_B(self, data1):  # B旋转图像更新
        self.time_xyz_B = data1
        # 直接使用内存视图加速
        self.data_3D_B.clear()
        self.data_3D_B = [None] * len(self.time_xyz_B)

        for i in range(len(self.time_xyz_B)):
            self.data_3D_B[i] = QScatterDataItem(QVector3D(
                self.time_xyz_B[i, 1],
                self.time_xyz_B[i, 2],
                self.time_xyz_B[i, 3]
            ))
        self.series_B.dataProxy().resetArray(self.data_3D_B)

    # 时间轴滚动定时事件
    def showtime3(self):
        # 动态滚动图表 QChart 对象
        if self.time3_jd == 0:
            self.axis_x_A.setMin(QDateTime.currentDateTime().addSecs(-self.fanwei))
            self.time3_jd = 1
        elif self.time3_jd == 1:
            self.axis_x_A.setMax(QDateTime.currentDateTime())
            self.time3_jd = 2
        elif self.time3_jd == 2:
            self.axis_x_B.setMin(QDateTime.currentDateTime().addSecs(-self.fanwei))
            self.time3_jd = 3
        elif self.time3_jd == 3:
            self.axis_x_B.setMax(QDateTime.currentDateTime())
            self.time3_jd = 0

    # 更新数据大小（删除数据，控制内存大小）
    def showtime4(self):
        # 判断时间间隔，大于300秒，从数据库更新数据
        if self.time4_last_time.secsTo(QDateTime.currentDateTime()) >= 300:
            if self.big_arr_a > int(self.lineEdit1_72.text()):     # 判断数据是否超出设定数据
                # 更新二维数据 获取所有的数据系列
                series_list_A = self.line_chart_A.series()
                # 移除每一个系列
                for series in series_list_A:
                    self.line_chart_A.removeSeries(series)
                    # 如果需要，也可以删除系列的关联对象
                    del series
                self.time_xyz_A = None
                self.data_3D_A.clear()
                self.series_A.dataProxy().resetArray(self.data_3D_A)  # 排空3D绘制界面
                self.chart_view_A.time_key = self.dele_time_data_ini_A()  # 实时数据初始化方法 同时更新3维数据大小

            if self.big_arr_a > int(self.lineEdit1_72.text()):  # 判断数据是否超出设定数据
                # 获取所有的数据系列
                series_list_B = self.line_chart_B.series()
                # 移除每一个系列
                for series in series_list_B:
                    self.line_chart_B.removeSeries(series)
                    # 如果需要，也可以删除系列的关联对象
                    del series
                self.time_xyz_B = None
                self.data_3D_B.clear()
                self.series_B.dataProxy().resetArray(self.data_3D_B)  # 排空3D绘制界面
                self.chart_view_B.time_key = self.dele_time_data_ini_B()  # 实时数据初始化方法 同时更新3维数据大小
            self.time4_last_time = QDateTime.currentDateTime()

    # --------------------多线程任务-------------------
    # def thread_start(self):  # 多线程
    #     print("time start")
    #     self.timer.start(cycle_1)  # 定时器运行开始并时间设定
    #
    # def thread_finished(self):  # 多线程结束
    #     print("time stop")
    #     self.timer.stop()
    #     self.Auto_data_generation(To_be_allocated_name)

    # ------------------输入框动作函数-----------------
    def lineEdit1_change(self):  # opcurl输入框改变值动作
        global url
        url = self.lineEdit1.text()
        print(url)

    def lineEdit1_2_change(self):  # opc账号输入框改变值动作
        global opc_username
        opc_username = self.lineEdit1_2.text()
        print(opc_username)

    def lineEdit1_3_change(self):  # opc密码输入框改变值动作
        global opc_password
        opc_password = self.lineEdit1_3.text()
        print(opc_password)

    def lineEdit1_5_change(self):  # A枪CNC地址输入框改变值动作
        global ipA
        ipA = self.lineEdit1_5.text()
        print(ipA)

    def lineEdit1_6_change(self):  # A枪CNC端口输入框改变值动作
        global portA
        portA = int(self.lineEdit1_6.text())
        print(portA)

    def lineEdit1_8_change(self):  # A枪CNC地址输入框改变值动作
        global ipB
        ipB = self.lineEdit1_8.text()
        print(ipB)

    def lineEdit1_7_change(self):  # A枪CNC端口输入框改变值动作
        global portB
        portB = int(self.lineEdit1_7.text())
        print(portB)

    def lineEdit1_9_change(self):  # 数据库库名输入框改变值动作
        global servermy
        servermy = self.lineEdit1_9.text()
        print(servermy)

    def lineEdit1_10_change(self):  # 数据库端口输入框改变值动作
        global portmy
        portmy = self.lineEdit1_10.text()
        print(portmy)

    def lineEdit1_11_change(self):  # 数据库账号输入框改变值动作
        global usermy
        usermy = self.lineEdit1_11.text()
        print(usermy)

    def lineEdit1_4_change(self):  # 数据库密码输入框改变值动作
        global passwordmy
        passwordmy = self.lineEdit1_4.text()
        print(passwordmy)

    def lineEdit1_12_change(self):  # 数据库表名输入框改变值动作
        global databasemy
        databasemy = self.lineEdit1_12.text()
        print(databasemy)

    def lineEdit1_13_change(self):  # 数据库新建库名输入框改变值动作
        global newdatabasemy
        newdatabasemy = self.lineEdit1_13.text()
        print(newdatabasemy)

    def lineEdit1_14_change(self):  # 数据库新建表名输入框改变值动作
        global newtable
        newtable = self.lineEdit1_14.text()
        print(newtable)

    def textEdit1_change(self):  # 新建数据表内容被更改动作
        new_text = self.textEdit1.toPlainText()
        self.lineEdit1_14.setText(self.comboBox_10.currentData())
        sqls = self.load_sqls()
        for sql in sqls:
            if sql['Variable'] == self.comboBox_10.currentText():
                sql['data'] = new_text
        self.save_sqls(sqls)

    def lineEdit1_15_change(self):  # 执行周期秒数输入框改变值动作
        global cycle_1
        cycle_1 = int(self.lineEdit1_15.text())
        print(cycle_1)

    def lineEdit1_3Dfanwei_change(self, neiron, number):  # 3D范围设置
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'

        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            data1 = json.load(file)

        data1["3Dline"][neiron] = int(number.text())
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性

        axis = self.surface.axisX()  # 三轴初始化
        axis.setRange(data1["3Dline"]["X_min"], data1["3Dline"]["X_max"])  # 设置X轴范围
        axis = self.surface.axisY()
        axis.setRange(data1["3Dline"]["Z_min"], data1["3Dline"]["Z_max"])
        axis = self.surface.axisZ()
        axis.setRange(data1["3Dline"]["Y_min"], data1["3Dline"]["Y_max"])

    def lineEdit1_72_change(self, neiron, number):  # 其他设置
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'

        # 从 JSON 文件读取字典
        with open(json_file, 'r') as file:
            data1 = json.load(file)

        data1["other"][neiron] = int(number.text())
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性

    # ---------------------------------------------

    # -------------------选中曲线 多选按钮点中-------------------
    def update_status(self):
        checkboxed = {self.checkBox_2.text(): self.checkBox_2.isChecked(),
                      self.checkBox_3.text(): self.checkBox_3.isChecked(),
                      self.checkBox_4.text(): self.checkBox_4.isChecked(),
                      self.checkBox_5.text(): self.checkBox_5.isChecked(),
                      self.checkBox_6.text(): self.checkBox_6.isChecked(),
                      self.checkBox_11.text(): self.checkBox_11.isChecked(),
                      self.checkBox_12.text(): self.checkBox_12.isChecked(),
                      self.checkBox_13.text(): self.checkBox_13.isChecked(),
                      self.checkBox_14.text(): self.checkBox_14.isChecked(),
                      self.checkBox_15.text(): self.checkBox_15.isChecked(),
                      self.checkBox_16.text(): self.checkBox_16.isChecked(),
                      self.checkBox_17.text(): self.checkBox_17.isChecked(),
                      self.checkBox_18.text(): self.checkBox_18.isChecked(),
                      self.checkBox_19.text(): self.checkBox_19.isChecked(),
                      self.checkBox_7.text(): self.checkBox_7.isChecked(),
                      self.checkBox_8.text(): self.checkBox_8.isChecked(),
                      self.checkBox_9.text(): self.checkBox_9.isChecked(),
                      self.checkBox_10.text(): self.checkBox_10.isChecked()
                      }

        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/legend.json'

        # 检查文件是否存在
        if os.path.exists(json_file):
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                data1 = json.load(file)
        else:
            # 如果文件不存在，初始化一个新的字典
            data = {}
        data = checkboxed
        # 当前数据的更新缓存
        self.indexed_items = list(data.items())
        self.chart_view_A.key_v_data = self.indexed_items
        self.chart_view_B.key_v_data = self.indexed_items
        if data1 != data:   # 更新二维图表
            # 获取所有的数据系列
            series_list_A = self.line_chart_A.series()
            # 移除每一个系列
            for series in series_list_A:
                self.line_chart_A.removeSeries(series)
                # 如果需要，也可以删除系列的关联对象
                del series
            # 获取所有的数据系列
            series_list_B = self.line_chart_B.series()
            # 移除每一个系列
            for series in series_list_B:
                self.line_chart_B.removeSeries(series)
                # 如果需要，也可以删除系列的关联对象
                del series
            self.update_R_time_data_ini_A()  # 实时数据初始化方法
            self.update_R_time_data_ini_B()  # 实时数据初始化方法
            # 初始化输出
        for i in data.keys():
            data1[i] = data[i]
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            # print(data)
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性

    # ---------------------曲线滚动选择项-----------------------
    def time_update_status(self):
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'
        # 检查文件是否存在
        if os.path.exists(json_file):
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                data1 = json.load(file)
        data1["other"]["实时图像滚动"] = self.checkBox_20.isChecked()
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            # print(data)
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性
        if self.checkBox_20.isChecked():
            # 开始进行定时任务
            self.timer3.start(cycle_1 * 5)  # 定时器运行开始并时间设定
        else:
            self.timer3.stop()

    # ---------------------清除数据方式选择项-----------------------
    def clear_data_update_status(self):
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'
        # 检查文件是否存在
        if os.path.exists(json_file):
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                data1 = json.load(file)
        data1["other"]["定时清数据"] = self.radioButton.isChecked()
        data1["other"]["开门清数据"] = self.radioButton_2.isChecked()
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            # print(data)
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性


    # ---------------------显示数据范围选择项-----------------------
    def Display_Range_update_status(self):
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'
        # 检查文件是否存在
        if os.path.exists(json_file):
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                data1 = json.load(file)
        data1["other"]["仅下束"] = self.radioButton_3.isChecked()
        data1["other"]["全部"] = self.radioButton_4.isChecked()
        if self.radioButton_3.isChecked():
            self.worker.D_Range_IN.emit(0)
        elif self.radioButton_4.isChecked():
            self.worker.D_Range_IN.emit(1)
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            # print(data)
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性

    # ---------------------保存数据范围选择项-----------------------
    def Save_scope_update_status(self):
        # 指定要操作的JSON文件名
        json_file = 'H_S_JSON/System_settings.json'
        # 检查文件是否存在
        if os.path.exists(json_file):
            # 从 JSON 文件读取字典
            with open(json_file, 'r') as file:
                data1 = json.load(file)
        data1["other"]["仅焊接"] = self.radioButton_5.isChecked()
        data1["other"]["所有下束"] = self.radioButton_6.isChecked()
        data1["other"]["全部数据"] = self.radioButton_7.isChecked()
        if self.radioButton_5.isChecked():
            self.worker.S_scope_IN.emit(0)
        elif self.radioButton_6.isChecked():
            self.worker.S_scope_IN.emit(1)
        elif self.radioButton_7.isChecked():
            self.worker.S_scope_IN.emit(2)
        # 输出当前数据
        # print("当前数据:", data)
        # 将更新后的字典写入 JSON 文件
        with open(json_file, 'w') as file:
            # print(data)
            json.dump(data1, file, indent=4)  # indent 参数用于格式化输出，增加可读性

    # --------------------滑动条改变事件------------------------
    def Slidervalue_Changed(self):
        self.fanwei = self.verticalSlider.value()  # 获得滑动条设置的显示时间范围
        # # 创建 QDateTimeAxis 实例并设置格式
        self.axis_x_A.setMin(QDateTime.currentDateTime().addSecs(-self.fanwei))
        self.axis_x_A.setMax(QDateTime.currentDateTime())
        self.axis_x_B.setMin(QDateTime.currentDateTime().addSecs(-self.fanwei))
        self.axis_x_B.setMax(QDateTime.currentDateTime())
        self.label_8.setText(str(round(self.fanwei / 60)) + "分钟")

    # ------------------按钮动作函数-----------------
    def pushButton1_clicked(self):  # opc连接动作
        try:
            global client
            client = Client(url)
            client.set_user(opc_username)
            client.set_password(opc_password)
            res = client.connect()
            self.label_6.setStyleSheet("color: green")
            self.label_6.setText('opcua连接成功')
        finally:
            self.label_6.setStyleSheet("color: red")
            self.label_6.setText('opcua连接错误')
            print("opcua连接错误")

    def pushButton1_2_clicked(self):  # OPCUA链接断开
        global client
        client.disconnect()
        self.label_6.setStyleSheet("color: black")
        self.label_6.setText('opcua断开')

    def pushButton1_13_clicked(self):  # OPCUA获取节点
        global client
        root = client.get_root_node()

        # 节点获取模块
        # 递归打印所有节点信息
        def print_node_info(nodes, indent=0):
            self.textEdit1_2.insertPlainText("  " * indent, nodes.nodeid)
            print("  " * indent, nodes.nodeid)
            for child in nodes.get_children():
                print_node_info(child, indent + 1)

        # 从根节点开始打印所有节点信息
        print_node_info(root)

    def pushButton1_4_clicked(self):  # A枪CNC连接
        print(f"connecting to machine at {ipA}:{portA}...")
        ret = focas.cnc_allclibhndl3(
            ipA.encode(),
            portA,
            timeout,
            ctypes.byref(libhA),
        )
        if ret != 0:
            self.label_9.setStyleSheet("color: red")
            self.label_9.setText('cnc链接失败')
            raise Exception(f"Failed to connect to A枪cnc! ({ret})")
        else:
            self.label_9.setStyleSheet("color: green")
            self.label_9.setText('cnc链接成功')

    def pushButton1_3_clicked(self):  # A枪CNC断开
        ret = focas.cnc_freelibhndl(libhA)
        self.label_9.setStyleSheet("color: black")
        self.label_9.setText('cnc断开')
        print(ret)

    def pushButton1_6_clicked(self):  # B枪CNC连接
        print(f"connecting to machine at {ipB}:{portB}...")
        ret = focas.cnc_allclibhndl3(
            ipB.encode(),
            portB,
            timeout,
            ctypes.byref(libhB),
        )
        if ret != 0:
            self.label_16.setText('cnc链接失败')
            self.label_16.setStyleSheet("color: red")
            raise Exception(f"Failed to connect to B枪cnc! ({ret})")
        else:
            self.label_16.setStyleSheet("color: green")
            self.label_16.setText('cnc链接成功')

    def pushButton1_5_clicked(self):  # B枪CNC断开
        ret = focas.cnc_freelibhndl(libhB)
        self.label_16.setStyleSheet("color: black")
        self.label_16.setText('cnc断开')
        print(ret)

    def pushButton1_15_clicked(self):  # CNC数据获取
        if self.comboBox_2.currentText() == "A枪":  # 获得枪状态
            libh = libhA
        else:
            libh = libhB
        get_tb = self.comboBox_3.currentData()  # 获得轴状态
        try:  #尝试获取值并输出打印
            if self.comboBox.currentText() == "绝对位置":
                tofs = ODBAXIS()
                ret = focas.cnc_absolute(libh, int(get_tb), 24, ctypes.byref(tofs))
            elif self.comboBox.currentText() == "速度":
                tofs = ODBACT()
                ret = focas.cnc_actf(libh, int(get_tb), 24, ctypes.byref(tofs))
            else:
                self.label_46.setStyleSheet("color: red")
                self.label_46.setText("获取失败")
            tofs_id = "-".join([f"{tofs.data[i]}" for i in range(5)])
            self.textEdit1_2.insertPlainText(f"position={tofs_id}")
            print(f"position={tofs_id}")
        finally:
            ret = focas.cnc_freelibhndl(libh)
            if ret != 0:
                raise Exception(f"Failed to free library handle! ({ret})")

    def pushButton1_8_clicked(self):  # 数据库连接
        # 连接到SQL Server  host='localhost:1433'   server='DESKTOP-3BQ74EF'   , charset='CP936'  port='1433'
        try:

            self.conn = pymssql.connect(server=servermy, port=portmy, user=usermy, password=passwordmy, database=databasemy,
                                   charset='utf8')
            self.label_20.setStyleSheet("color: green")
            self.label_20.setText('数据库链接成功')
            print("成功")
            print(self.conn)
            self.cursor = self.conn.cursor()
            print(self.cursor)

        except:
            self.label_20.setStyleSheet("color: red")
            self.label_20.setText('数据库链接失败')
            print("失败")

    def pushButton1_7_clicked(self):  # 数据库断开
        # 数据库关闭游标和连接
        self.cursor.close()
        self.conn.close()
        print(self.conn)
        print(self.cursor)
        self.label_20.setStyleSheet("color: black")
        self.label_20.setText('数据库断开')

    def pushButton1_9_clicked(self):  # 新建数据库
        try:
            # 数据库关闭游标和连接
            # self.conn = pymssql.connect(server=servermy, user=usermy, password=passwordmy, timeout=100)
            # # 数据库链接
            # self.cursor = self.conn.cursor(as_dict=True)
            # self.conn.autocommit(True)  # 设置是否自动提交事务
            global newdatabasemy
            # 查看现有数据库
            sql = "SELECT * FROM SYSDATABASES"
            self.cursor.execute(sql)
            print("现有数据库：")
            while True:
                row = self.cursor.fetchone()
                if row is None:
                    break
                print(row['name'])
            # 创建数据库
            sql = '''
            IF NOT EXISTS (SELECT * FROM SYSDATABASES WHERE NAME = \'%s\')
            CREATE DATABASE %s;
            ''' % (newdatabasemy, newdatabasemy)
            self.cursor.execute(sql)

            # 查看现有数据库
            sql = "SELECT * FROM SYSDATABASES"
            self.cursor.execute(sql)
            print("现有数据库：")
            while True:
                row = self.cursor.fetchone()
                if row is None:
                    break
                print(row['name'])
            # 关闭游标与数据库连接
            self.cursor.close()
            self.conn.close()
            self.label_31.setStyleSheet("color: green")
            self.label_31.setText('新建成功')
        except:
            self.label_31.setStyleSheet("color: red")
            self.label_31.setText('新建失败')

    def pushButton1_10_clicked(self):  # 新建表
        global cursor
        global conn
        # conn = pymssql.connect(server=servermy, user=usermy, password=passwordmy, database=newdatabasemy)
        # # 数据库链接
        # cursor = conn.cursor()
        # conn.autocommit(True)

        # 查看现有表
        sql = "SELECT NAME FROM TESTDB.SYS.TABLES"
        msg = self.cursor.execute(sql)
        print(self.cursor.fetchall())
        newtablename = self.lineEdit1_14.text()
        self.cursor.execute("DROP TABLE IF EXISTS [%s]" % newtablename)  # 如果存在此表，则删除

        # 创建表
        newList_Template = self.textEdit1.toPlainText()
        sql = """
        USE TestDB
        CREATE TABLE [%s](
        %s
        )
        """ % (newtablename, newList_Template)
        self.cursor.execute(sql)

        # 查看现有表
        sql = "SELECT NAME FROM TESTDB.SYS.TABLES"
        self.cursor.execute(sql)
        print(self.cursor.fetchall())
        self.conn.commit()
        # 关闭游标与数据库连接
        # cursor.close()
        # conn.close()
        self.label_31.setStyleSheet("color: black")
        # self.label_20.setText('数据库断开')

    # 文件结构：
    # 坯组编号        边号
    #   详细数据
    #        1
    #        2
    #   原料信息
    #      板坯号1
    #      板坯号2
    def pushButton1_26_clicked(self):      # 生产报表条件查询按钮事件绑定
        self.current_button = None
        self.tableWidget_2.clear()
        self.tableWidget_3.clear()
        query1 = """
            SELECT p.坯组编号, p.边号, p.操作员, p.填写时间, p.开始时间, p.结束时间
            FROM production p
            """
        liemin1 = ["坯组编号", "边号", "操作员", "填写时间", "开始时间", "结束时间", "查询详情"]
        query2 = """
            SELECT m.坯组编号, m.板坯编号, m.板坯顺序, m.原料材质, m.原料长度, m.原料宽度, m.原料厚度, m.备注
            FROM material m
            """
        liemin2 = ["坯组编号", "板坯编号", "板坯顺序", "原料材质", "原料长度", "原料宽度", "原料厚度", "备注"]

        pizu = self.comboBox_6.currentText()
        caizhi = self.comboBox_8.currentText()
        banpi = self.comboBox_7.currentText()
        caozuo = self.comboBox_9.currentText()
        conditions1 = []
        conditions2 = []
        params1 = []
        params2 = []

        if pizu != "":
            conditions1.append("p.坯组编号 = %s")
            conditions2.append("m.坯组编号 = %s")
            params1.append(pizu)
            params2.append(pizu)

        if caizhi != "":
            if pizu == "":
                self.cursor.execute("SELECT 坯组编号 FROM material WHERE 原料材质=%s", (caizhi,))  # 获取原料确定情况下对应的坯组编号信息
                results = self.cursor.fetchall()  # 获取查询到的所有信息
                results_zh = np.transpose(results)  # np.transpose行列转换
                poi = []
                for i in results_zh[0]:
                    if i == pizu:
                        continue
                    poi.append("p.坯组编号 = %s")
                    params1.append(i)
                conditions1.append("(" + " OR ".join(poi) + ")")
            conditions2.append("m.原料材质 = %s")
            params2.append(caizhi)

        if banpi != "":
            if pizu == "":
                self.cursor.execute("SELECT 坯组编号 FROM material WHERE 板坯编号=%s", (banpi,))  # 获取板坯编号确定情况下对应的坯组编号信息
                results = self.cursor.fetchall()  # 获取查询到的所有信息
                self.conn.commit()
                results_zh = np.transpose(results)  # np.transpose行列转换
                poi = []
                for i in results_zh[0]:
                    if i == pizu:
                        continue
                    poi.append("p.坯组编号 = %s")
                    params1.append(i)
                conditions1.append("(" + " OR ".join(poi) + ")")
            conditions2.append("m.板坯编号 = %s")
            params2.append(banpi)

        if caozuo != "":
            if pizu == "":
                self.cursor.execute("SELECT 坯组编号 FROM production WHERE 操作员=%s", (caozuo,))  # 获取操作员确定情况下对应的坯组编号信息
                results = self.cursor.fetchall()  # 获取查询到的所有信息
                self.conn.commit()
                results_zh = np.transpose(results)  # np.transpose行列转换
                unique_pizu = np.unique(results_zh[0])  # 坯组编号去重计算
                poi = []
                for i in unique_pizu:
                    if i == pizu:
                        continue
                    poi.append("m.坯组编号 = %s")
                    params2.append(i)
                conditions2.append("(" + " OR ".join(poi) + ")")

            conditions1.append("p.操作员 = %s")
            params1.append(caozuo)

        if conditions1:
            query1 += " WHERE " + " AND ".join(conditions1)
        if conditions2:
            query2 += " WHERE " + " AND ".join(conditions2)

        print("查询字符串:", query1)
        print("查询字符串:", query2)
        print("参数:", params1)
        print("参数:", params2)

        self.cursor.execute(query1, params1)
        results1 = self.cursor.fetchall()  # 获取查询到的所有信息
        self.conn.commit()

        self.cursor.execute(query2, params2)
        results2 = self.cursor.fetchall()  # 获取查询到的所有信息
        self.conn.commit()

        # results_zh = np.transpose(results)  # np.transpose行列转换
        # unique_pizu = np.unique(results_zh[0])  # 坯组编号去重计算
        print(results1)
        print(results2)
        if results1 == [] or results2 == []:
            self.label_79.setStyleSheet("color: red")
            self.label_79.setText('查询为空，请更换条件')
        else:
            self.tableWidget_2.setRowCount(len(results1))  # 设置行数
            self.tableWidget_2.setColumnCount(7)  # 设置列数
            self.tableWidget_3.setRowCount(len(results2))  # 设置行数
            self.tableWidget_3.setColumnCount(8)  # 设置列数
            self.tableWidget_2.setHorizontalHeaderLabels(liemin1)  # 设置列名称
            self.tableWidget_3.setHorizontalHeaderLabels(liemin2)  # 设置列名称

            for rows, resultrow in enumerate(results1):  # 对数据集合中的每行进行操作
                pizubianhao = resultrow[0]  # 坯组编号信息
                bianhao = resultrow[1]  # 边号信息
                button = QPushButton("详细数据")
                self.tableWidget_2.setCellWidget(rows, 6, button)  # 在第 7 列插入按钮
                button.clicked.connect(lambda _, p=pizubianhao, b=bianhao, btn=button: self.on_button_click(p, b, btn))
                for cols, resultcol in enumerate(resultrow):
                    if cols == 2:
                        item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_2.setItem(rows, cols, item_a)
                    else:
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_2.setItem(rows, cols, item_a)
            self.tableWidget_2.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget_2)  # 合并首列同类项

            for rows, resultrow in enumerate(results2):  # 对数据集合中的每行进行操作
                for cols, resultcol in enumerate(resultrow):
                    if cols == 7:
                        item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_3.setItem(rows, cols, item_a)
                    else:
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_3.setItem(rows, cols, item_a)
            self.tableWidget_3.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget_3)  # 合并首列同类项
            self.label_79.setStyleSheet("color: green")
            self.label_79.setText('查询成功')

    def pushButton1_21_clicked(self):  # 生产报表时间查询按钮事件绑定
        self.current_button = None
        self.tableWidget_2.clear()
        self.tableWidget_3.clear()
        starttime = self.dateTimeEdit_3.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        overtime = self.dateTimeEdit_4.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        print(starttime)
        print(overtime)
        query1 = """
                    SELECT p.坯组编号, p.边号, p.操作员, p.填写时间, p.开始时间, p.结束时间
                    FROM production p WHERE p.填写时间>%s AND p.填写时间<%s
                    """
        liemin1 = ["坯组编号", "边号", "操作员", "填写时间", "开始时间", "结束时间", "表格", "图像"]
        query2 = """
                    SELECT m.坯组编号, m.板坯编号, m.板坯顺序, m.原料材质, m.原料长度, m.原料宽度, m.原料厚度, m.备注
                    FROM material m
                    """
        liemin2 = ["坯组编号", "板坯编号", "板坯顺序", "原料材质", "原料长度", "原料宽度", "原料厚度", "备注"]

        conditions2 = []
        params1 = [starttime, overtime]
        params2 = []
        self.cursor.execute(query1, params1)
        results1 = self.cursor.fetchall()  # 获取查询到的所有信息
        self.conn.commit()

        print("查询字符串:", query1)
        print("查询字符串:", query2)
        print("参数:", params1)
        print("参数:", params2)

        if results1 == []:
            self.label_79.setStyleSheet("color: red")
            self.label_79.setText('查询为空，请更换条件')
        else:
            results_zh = np.transpose(results1)                    # np.transpose行列转换
            unique_pizu = np.unique(results_zh[0])                 # 坯组编号去重计算
            poi = []
            for i in unique_pizu:
                poi.append("m.坯组编号 = %s")
                params2.append(i)
            conditions2.append("(" + " OR ".join(poi) + ")")
            if conditions2:
                query2 += " WHERE " + " AND ".join(conditions2)
            self.cursor.execute(query2, params2)
            results2 = self.cursor.fetchall()                      # 获取查询到的所有信息
            self.conn.commit()
            self.tableWidget_2.setRowCount(len(results1))
            self.tableWidget_2.setColumnCount(len(results1[0]) + 1)
            self.tableWidget_3.setRowCount(len(results2))
            self.tableWidget_3.setColumnCount(len(results2[0]))
            self.tableWidget_2.setHorizontalHeaderLabels(liemin1)  # 设置列名称
            self.tableWidget_3.setHorizontalHeaderLabels(liemin2)  # 设置列名称

            for rows, resultrow in enumerate(results1):            # 对数据集合中的每行进行操作
                pizubianhao = resultrow[0]                         # 坯组编号信息
                bianhao = resultrow[1]                             # 边号信息
                button = QPushButton(f"Button {rows + 1}")
                self.tableWidget_2.setCellWidget(rows, 6, button)  # 在第 7 列插入按钮
                button.clicked.connect(lambda _, p=pizubianhao, b=bianhao, btn=button: self.on_button_click(p, b, btn))
                for cols, resultcol in enumerate(resultrow):
                    if cols == 2:
                        item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_2.setItem(rows, cols, item_a)
                    else:
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_2.setItem(rows, cols, item_a)
            self.tableWidget_2.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget_2)  #合并首列同类项

            for rows, resultrow in enumerate(results2):  # 对数据集合中的每行进行操作
                for cols, resultcol in enumerate(resultrow):
                    if cols == 7:
                        item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_3.setItem(rows, cols, item_a)
                    else:
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_3.setItem(rows, cols, item_a)
            self.tableWidget_3.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget_3)  # 合并首列同类项
            self.label_79.setStyleSheet("color: green")
            self.label_79.setText('查询成功')

    def pushButton1_27_clicked(self):  # 详情数据数据库按条件查询按钮
        self.label_80.setStyleSheet("color: red")
        self.label_80.setText('获取中，请稍候')
        self.tableWidget.clear()
        query1_A = """
                SELECT p.坯组编号, p.边号, p.日期时间, p.[聚焦显示(V)], p.[偏压显示(V)], p.[灯丝显示(A)], p.[高压显示(KV)], p.[束流显示(MA)],
                       p.扫描频率, p.扫描X轴, p.扫描Y轴, p.偏转X轴, p.偏转Y轴, p.合轴X轴, p.合轴Y轴, p.像散X轴, p.像散Y轴, p.枪室真空度, p.焊室真空度, 
                       p.R角度, p.转台角度, p.X坐标, p.Y坐标, p.Z坐标
                FROM persons_A p
                """
        query1_B = """
                SELECT p1.坯组编号, p1.边号, p1.日期时间, p1.[聚焦显示(V)], p1.[偏压显示(V)], p1.[灯丝显示(A)], p1.[高压显示(KV)], p1.[束流显示(MA)],
                       p1.扫描频率, p1.扫描X轴, p1.扫描Y轴, p1.偏转X轴, p1.偏转Y轴, p1.合轴X轴, p1.合轴Y轴, p1.像散X轴, p1.像散Y轴, p1.枪室真空度, p1.焊室真空度, 
                       p1.R角度, p1.转台角度, p1.X坐标, p1.Y坐标, p1.Z坐标
                FROM persons_B p1
                """
        liemin1 = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)",
                   "扫描频率", "扫描X轴", "扫描Y轴", "偏转X轴", "偏转Y轴", "合轴X轴", "合轴Y轴", "像散X轴", "像散Y轴",
                   "枪室真空度", "焊室真空度", "R角度", "转台角度"]

        pizu = self.comboBox_4.currentText()  # 坯组编号信息获取
        bianhao = self.comboBox_11.currentText()  # 边号信息获取
        caozuo = self.comboBox_5.currentText()  # 操作信息获取
        conditions1_A = []  # A坯组逻辑语句
        params1_A = []  # A坯组逻辑对应变量
        conditions1_B = []  # B坯组逻辑语句
        params1_B = []  # B坯组逻辑对应变量

        if pizu != "":
            if pizu[0] == "A":
                conditions1_A.append("p.坯组编号 = %s")
                params1_A.append(pizu)
            elif pizu[0] == "B":
                conditions1_B.append("p1.坯组编号 = %s")
                params1_B.append(pizu)

        if caozuo != "":
            self.cursor.execute("SELECT 坯组编号 FROM production WHERE 操作员=%s", (caozuo,))  # 获取操作员确定情况下对应的坯组编号信息
            results = self.cursor.fetchall()  # 获取查询到的所有信息
            self.conn.commit()
            results_zh = np.transpose(results)  # np.transpose行列转换
            unique_pizu = np.unique(results_zh[0])  # 坯组编号去重计算
            poi_A = []
            poi_B = []
            for i in unique_pizu:
                if i == pizu:
                    continue
                if i[0] == "A":
                    poi_A.append("p.坯组编号 = %s")
                    params1_A.append(i)
                elif i[0] == "B":
                    poi_B.append("p1.坯组编号 = %s")
                    params1_B.append(i)
            if pizu != "":
                params1_A.clear()
                conditions1_A.clear()
                params1_B.clear()
                conditions1_B.clear()
                if pizu[0] == "A":
                    params1_A.append(pizu)
                elif pizu[0] == "B":
                    params1_B.append(pizu)
            if params1_A:
                poi_A.append("p.坯组编号 = %s")
                conditions1_A.append("(" + " OR ".join(poi_A) + ")")
            if params1_B:
                poi_B.append("p1.坯组编号 = %s")
                conditions1_B.append("(" + " OR ".join(poi_B) + ")")

        if bianhao != "":
            if pizu != "":
                if pizu[0] == "A":
                    conditions1_A.append("p.边号 = %s")
                    params1_A.append(bianhao)
                elif pizu[0] == "B":
                    conditions1_B.append("p1.边号 = %s")
                    params1_B.append(bianhao)

        if conditions1_A:
            query1_A += " WHERE " + " AND ".join(conditions1_A)

        if conditions1_B:
            query1_B += " WHERE " + " AND ".join(conditions1_B)

        print("查询字符串A:", query1_A)
        print("参数A:", params1_A)
        print("查询字符串B:", query1_B)
        print("参数B:", params1_B)

        try:
            print("len(params1_A)", len(params1_A))
            results1 = []
            results1_B = []
            if params1_A:
                print(len(params1_A))
                self.cursor.execute(query1_A, params1_A)
                results1 = self.cursor.fetchall()  # 获取查询到的所有信息
                self.conn.commit()
            if params1_B:
                self.cursor.execute(query1_B, params1_B)
                results1_B = self.cursor.fetchall()  # 获取查询到的所有信息
                self.conn.commit()
            if results1:
                if results1_B:
                    print(232323)
                    results1 = results1 + results1_B  # 两个表中都有数据就合并
            else:
                if results1_B:
                    print(45454545)
                    results1 = results1_B  # 只有表2中都有数据就单独摘出表二数据
            # print(results1)
            if not results1:
                self.label_80.setStyleSheet("color: red")
                self.label_80.setText('查询为空，请更换条件')
            else:
                # 遍历二维数组，将第三列的 datetime 转换为字符串
                # 确保 results1 是可以修改的  改为results2数组存储数据
                results2 = [list(row) for row in results1]  # 将每个元组转换为列表
                results3 = [list(row) for row in results1]
                # print(results2)
                for row2 in results3:
                    # 将第三列的 datetime 转换为字符串
                    row2[2] = row2[2].strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                for row1 in results2:
                    #转换为 Qdatetime
                    row1[2] = QDateTime(row1[2].date(), row1[2].time())  # 转为Qdatetime
                global results0_1  #存储最终转化的字典信息
                results0_1.clear()
                global results1_1
                #生成字典数据：坯组编号作为第一层字典键，边号作为第二层字典键，对数据进行存储，之后发送至图像显示
                # 使用 defaultdict 动态生成字典
                results0_1 = defaultdict(list)
                for row in results2:
                    key = row[0]  # 第一列作为键
                    values = row[1:]  # 其余列作为值
                    results0_1[key].append(values)  # 将值添加到对应键的列表中

                # 将 defaultdict 转换为普通字典
                results0_1 = dict(results0_1)
                # print(result)
                for key, values in results0_1.copy().items():
                    # 动态生成字典
                    results = defaultdict(list)
                    for row in values:
                        key1 = row[0]  # 第一列作为键
                        values1 = row[1:]  # 其余列作为值
                        results[key1].append(values1)  # 将值添加到对应键的列表中
                    results = dict(results)
                    results0_1[key] = results

                self.tableWidget.setRowCount(len(results3))  # 设置行数
                self.tableWidget.setColumnCount(21)  # 设置列数
                self.tableWidget.setHorizontalHeaderLabels(liemin1)  # 设置列名称

                for rows, resultrow in enumerate(results3):  # 对数据集合中的每行进行操作
                    for cols, resultcol in enumerate(resultrow):
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget.setItem(rows, cols, item_a)
                self.tableWidget.resizeColumnsToContents()  # 设置自适应宽度
                self.label_80.setStyleSheet("color: green")
                self.label_80.setText('查询成功')
        except:
            self.label_80.setStyleSheet("color: red")
            self.label_80.setText('查询超限，请更换条件')

    def pushButton1_17_clicked(self):  # 详情数据数据库按时间查询按钮
        self.tableWidget.clear()
        starttime = self.dateTimeEdit.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        overtime = self.dateTimeEdit_2.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        query1_A = """
                SELECT p.坯组编号, p.边号, p.日期时间, p.[聚焦显示(V)], p.[偏压显示(V)], p.[灯丝显示(A)], p.[高压显示(KV)], p.[束流显示(MA)],
                       p.扫描频率, p.扫描X轴, p.扫描Y轴, p.偏转X轴, p.偏转Y轴, p.合轴X轴, p.合轴Y轴, p.像散X轴, p.像散Y轴, p.枪室真空度, p.焊室真空度, 
                       p.R角度, p.转台角度, p.X坐标, p.Y坐标, p.Z坐标
                FROM persons_A p
                WHERE p.日期时间>%s AND p.日期时间<%s
                """
        query1_B = """
                SELECT p1.坯组编号, p1.边号, p1.日期时间, p1.[聚焦显示(V)], p1.[偏压显示(V)], p1.[灯丝显示(A)], p1.[高压显示(KV)], p1.[束流显示(MA)],
                       p1.扫描频率, p1.扫描X轴, p1.扫描Y轴, p1.偏转X轴, p1.偏转Y轴, p1.合轴X轴, p1.合轴Y轴, p1.像散X轴, p1.像散Y轴, p1.枪室真空度, p1.焊室真空度, 
                       p1.R角度, p1.转台角度, p1.X坐标, p1.Y坐标, p1.Z坐标
                FROM persons_B p1
                WHERE p1.日期时间>%s AND p1.日期时间<%s
                """
        liemin1 = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)",
                   "扫描频率", "扫描X轴", "扫描Y轴", "偏转X轴", "偏转Y轴", "合轴X轴", "合轴Y轴", "像散X轴", "像散Y轴",
                   "枪室真空度", "焊室真空度", "R角度", "转台角度"]

        params1 = [starttime, overtime]

        self.cursor.execute(query1_A, params1)
        results1 = self.cursor.fetchall()  # A获取查询到的所有信息
        self.cursor.execute(query1_B, params1)
        results1_B = self.cursor.fetchall()  # B获取查询到的所有信息
        self.conn.commit()

        print("查询字符串A:", query1_A)
        print("查询字符串B:", query1_B)
        print("参数:", params1)
        if results1:
            if results1_B:
                results1 = results1 + results1_B  # 两个表中都有数据就合并
        else:
            if results1_B:
                results1 = results1_B  # 只有表2中都有数据就单独摘出表二数据
        if results1 == []:
            self.label_79.setStyleSheet("color: red")
            self.label_79.setText('查询为空，请更换条件')
        else:
            # 遍历二维数组，将第三列的 datetime 转换为字符串
            # 确保 results1 是可以修改的  改为results2数组存储数据
            results2 = [list(row) for row in results1]  # 将每个元组转换为列表
            results3 = [list(row) for row in results1]
            # print(results2)
            for row2 in results3:
                # 将第三列的 datetime 转换为字符串
                # print(row2)
                row2[2] = row2[2].strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
            for row1 in results2:
                # 转换为 Qdatetime
                row1[2] = QDateTime(row1[2].date(), row1[2].time())  # 转为Qdatetime

            global results0_1  # 存储最终转化的字典信息
            results0_1.clear()
            global results1_1
            # 生成字典数据：坯组编号作为第一层字典键，边号作为第二层字典键，对数据进行存储，之后发送至图像显示
            # 使用 defaultdict 动态生成字典
            results0_1 = defaultdict(list)
            print(results2)
            for row in results2:
                key = row[0]  # 第一列作为键
                values = row[1:]  # 其余列作为值
                results0_1[key].append(values)  # 将值添加到对应键的列表中

            # 将 defaultdict 转换为普通字典
            results0_1 = dict(results0_1)
            # print(result)
            for key, values in results0_1.copy().items():
                # 动态生成字典
                results = defaultdict(list)
                for row in values:
                    key1 = row[0]  # 第一列作为键
                    values1 = row[1:]  # 其余列作为值
                    results[key1].append(values1)  # 将值添加到对应键的列表中
                results = dict(results)
                # print(key)
                results0_1[key] = results
            self.tableWidget.setRowCount(len(results3))
            self.tableWidget.setColumnCount(len(results1[0]) + 1)
            self.tableWidget.setHorizontalHeaderLabels(liemin1)  # 设置列名称

            for rows, resultrow in enumerate(results3):  # 对数据集合中的每行进行操作
                for cols, resultcol in enumerate(resultrow):
                    item_a = QTableWidgetItem(str(resultcol))
                    item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                    self.tableWidget.setItem(rows, cols, item_a)
            self.tableWidget.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget)  # 合并首列同类项

            self.label_79.setStyleSheet("color: green")
            self.label_79.setText('查询成功')

    def pushButton1_18_clicked(self):  # 详细数据 输出PDF文件
        self.export_pdf(self.tableWidget, A1, "详情数据")

    def pushButton1_22_clicked(self):  # 生产数据 输出PDF文件
        self.export_pdf(self.tableWidget_2, A3, "生产数据")

    def pushButton1_25_clicked(self):  # 生产数据 输出PDF文件
        self.export_pdf(self.tableWidget_3, A3, "原料数据")

    def export_pdf(self, table_widget, size, name):
        """导出PDF的核心逻辑"""
        # 获取保存路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存PDF文件", name, "PDF文件 (*.pdf)")
        if not file_path:
            return

        # 提取表格数据
        data = []
        # 添加表头
        header = []
        for i in range(table_widget.columnCount()):
            header.append(table_widget.horizontalHeaderItem(i).text())
        data.append(header)

        # 添加表格内容
        for row in range(table_widget.rowCount()):
            row_data = []
            for col in range(table_widget.columnCount()):
                item = table_widget.item(row, col)
                row_data.append(item.text() if item else "")
            data.append(row_data)

        # 创建PDF文档
        doc = SimpleDocTemplate(file_path, pagesize=size)
        elements = []

        # 创建表格对象
        pdf_table = Table(data)

        # 设置表格样式
        style = TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.grey),  # 表头背景
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),  # 表头文字颜色

            ('ALIGN', (0, 0), (-1, -1), 'CENTER'),  # 居中对齐
            ('FONTNAME', (0, 0), (-1, -1), "ChineseFont"),  # 中文字体（需要系统支持）
            ('FONTSIZE', (0, 0), (-1, 0), 12),  # 表头字号

            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),  # 表头底部间距
            ('BACKGROUND', (0, 1), (-1, -1), colors.beige),  # 内容背景

            ('GRID', (0, 0), (-1, -1), 1, colors.black)  # 表格边框
        ])
        pdf_table.setStyle(style)

        elements.append(pdf_table)
        doc.build(elements)

        print(f"PDF已成功保存到：{file_path}")

    def render_page(self, painter, page, rows_per_page, scale):
        start_row = page * rows_per_page
        end_row = min(start_row + rows_per_page, self.tableWidget.rowCount())
        for row in range(start_row, end_row):
            for col in range(self.tableWidget.columnCount()):
                cell_item = self.tableWidget.item(row, col)
                cell_rect = self.tableWidget.visualItemRect(cell_item)
                print(cell_rect)
                # 调整每个单元格的绘制位置
                painter.save()
                painter.translate(0, (row - start_row) * cell_rect.height())
                self.tableWidget.render(painter, QPoint(0, 0), cell_rect)
                painter.restore()

    def export_to_excel(self):  #详细数据——数据库表格输出excel
        horizontalheaderitem = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)",
                                "扫描频率", "扫描X轴", "扫描Y轴", "偏转X轴", "偏转Y轴", "合轴X轴", "合轴Y轴", "像散X轴",
                                "像散Y轴",
                                "枪室真空度", "焊室真空度", "R角度", "转台角度"]
        path, _ = QFileDialog.getSaveFileName(self, "Save Excel", "设备详细数据", "Excel files (*.xlsx)")
        if path:
            workbook = Workbook()
            sheet = workbook.active
            for rolls, reatmm in enumerate(horizontalheaderitem):
                sheet.cell(row=1, column=rolls + 1).value = reatmm if reatmm else ""
            for row in range(self.tableWidget.rowCount()):
                for col in range(self.tableWidget.columnCount()):
                    item = self.tableWidget.item(row, col)
                    if col == 0 or col == 2:
                        sheet.cell(row=row + 2, column=col + 1).value = item.text() if item else ""
                        sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                      vertical='center')
                    else:
                        sheet.cell(row=row + 2, column=col + 1).value = float(item.text()) if item else ""
                        sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                      vertical='center')
            sheet.column_dimensions['A'].width = 11
            sheet.column_dimensions['B'].width = 6
            sheet.column_dimensions['C'].width = 25
            workbook.save(path)

    def shchen_to_excel(self):  #生产数据——数据库表格输出excel
        shchanshuju = ["坯组编号", "边号", "操作员", "填写时间", "开始时间", "结束时间"]
        banpishuju = ["坯组编号", "板坯编号", "板坯顺序", "原料材质", "原料长度", "原料宽度", "原料厚度", "备注"]
        path, _ = QFileDialog.getSaveFileName(self, "Save Excel", "生产数据", "Excel files (*.xlsx)")
        if path:
            workbook = Workbook()
            sheet = workbook.active
            sheet.title = "生产数据"
            # 创建一个新的工作表并重命名
            new_sheet = workbook.create_sheet(title='原料信息')
            for rolls, reatmm in enumerate(shchanshuju):
                sheet.cell(row=1, column=rolls + 1).value = reatmm if reatmm else ""
            for rolls, reatmm in enumerate(banpishuju):
                new_sheet.cell(row=1, column=rolls + 1).value = reatmm if reatmm else ""
            for row in range(self.tableWidget_2.rowCount()):  # 生产数据
                for col in range(self.tableWidget_2.columnCount()):
                    item = self.tableWidget_2.item(row, col)
                    if col == 1:
                        sheet.cell(row=row + 2, column=col + 1).value = int(item.text()) if item else ""
                        sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                      vertical='center')
                    else:
                        sheet.cell(row=row + 2, column=col + 1).value = item.text() if item else ""
                        sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                      vertical='center')

            for row in range(self.tableWidget_3.rowCount()):  # 原料信息
                for col in range(self.tableWidget_3.columnCount()):
                    item = self.tableWidget_3.item(row, col)
                    if col == 0 or col == 3 or col == 7:
                        new_sheet.cell(row=row + 2, column=col + 1).value = item.text() if item else ""
                        new_sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                          vertical='center')
                    else:
                        new_sheet.cell(row=row + 2, column=col + 1).value = float(item.text()) if item else ""
                        new_sheet.cell(row=row + 2, column=col + 1).alignment = Alignment(horizontal='center',
                                                                                          vertical='center')
            sheet.column_dimensions['A'].width = 11
            sheet.column_dimensions['D'].width = 25
            sheet.column_dimensions['E'].width = 25
            sheet.column_dimensions['F'].width = 25
            new_sheet.column_dimensions['A'].width = 11
            workbook.save(path)

    def actiondenglu_clicked(self):  #弹出登录窗口
        global window1
        window1 = ui_denglu()
        window1.show()

    def pushButton1_24_clicked(self):  #弹出历史数据图像窗口
        liemin = ["聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)", "枪室真空度", "焊室真空度", "R角度",
                  "转台角度"]
        global window3
        global results0_1
        window3 = MainWindow()
        window3.mianban = liemin
        window3.shuju = results0_1
        window3.show_chart()
        window3.show()

    def Auto_data_generation(self, To_be_allocated_name):  #弹出生产数据生成窗口
        global window2
        print(111111, To_be_allocated_name)
        window2 = Ui_shengchan(To_be_allocated_name)
        window2.show()

    def pushButton1_28_clicked(self):  # 待分配数据按临时编号查询
        self.label_83.setStyleSheet("color: red")
        self.label_83.setText('获取中，请稍候')
        self.tableWidget_4.clear()
        query1 = """
                        SELECT p.坯组编号, p.边号, p.日期时间, p.[聚焦显示(V)], p.[偏压显示(V)], p.[灯丝显示(A)], p.[高压显示(KV)], p.[束流显示(MA)], 
                                                           p.枪室真空度, p.焊室真空度, p.R角度, p.转台角度
                        FROM persons p
                        WHERE p.坯组编号 = %s
                        """
        liemin1 = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)"
            , "枪室真空度", "焊室真空度", "R角度", "转台角度"]

        pizu = self.comboBox_12.currentText()  # 坯组编号信息获取

        print("查询字符串:", query1)
        print("参数:", pizu)

        try:
            self.cursor.execute(query1, pizu)
            results1 = self.cursor.fetchall()  # 获取查询到的所有信息
            self.conn.commit()
            if results1 == []:
                self.label_83.setStyleSheet("color: red")
                self.label_83.setText('查询为空，请更换条件')
            else:
                self.tableWidget_4.setRowCount(len(results1))  # 设置行数
                self.tableWidget_4.setColumnCount(12)  # 设置列数
                self.tableWidget_4.setHorizontalHeaderLabels(liemin1)  # 设置列名称

                for rows, resultrow in enumerate(results1):  # 对数据集合中的每行进行操作
                    for cols, resultcol in enumerate(resultrow):
                        if (cols == 0):
                            item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                        else:
                            item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget_4.setItem(rows, cols, item_a)
                self.tableWidget_4.resizeColumnsToContents()  # 设置自适应宽度
                self.hebing(self.tableWidget_4)  # 合并首列同类项
                self.label_83.setStyleSheet("color: green")
                self.label_83.setText('查询成功')
        except:
            self.label_83.setStyleSheet("color: red")
            self.label_83.setText('查询超限，请更换条件')

    def pushButton1_29_clicked(self):  # 待分配数据按时间段号查询
        self.tableWidget_4.clear()
        starttime = self.dateTimeEdit_5.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        overtime = self.dateTimeEdit_6.dateTime().toString("yyyy-MM-dd HH:mm:ss")
        query1 = """
                    SELECT p.坯组编号, p.边号, p.日期时间, p.[聚焦显示(V)], p.[偏压显示(V)], p.[灯丝显示(A)], p.[高压显示(KV)], p.[束流显示(MA)], 
                           p.枪室真空度, p.焊室真空度, p.R角度, p.转台角度
                    FROM persons p
                    WHERE p.日期时间>%s AND p.日期时间<%s AND 坯组编号 LIKE N'%待分配%'
                    """
        liemin1 = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)",
                   "枪室真空度", "焊室真空度", "R角度", "转台角度"]

        params1 = [starttime, overtime]
        self.cursor.execute(query1, params1)
        results1 = self.cursor.fetchall()  # 获取查询到的所有信息
        self.conn.commit()

        print("查询字符串:", query1)
        print("参数:", params1)

        if results1 == []:
            self.label_83.setStyleSheet("color: red")
            self.label_83.setText('查询为空，请更换条件')
        else:
            self.tableWidget_4.setRowCount(len(results1))
            self.tableWidget_4.setColumnCount(len(results1[0]) + 1)
            self.tableWidget_4.setHorizontalHeaderLabels(liemin1)  # 设置列名称

            for rows, resultrow in enumerate(results1):  # 对数据集合中的每行进行操作
                for cols, resultcol in enumerate(resultrow):
                    if (cols == 0):
                        item_a = QTableWidgetItem(str(resultcol.encode('latin1').decode('gbk')))
                    else:
                        item_a = QTableWidgetItem(str(resultcol))
                    item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                    self.tableWidget_4.setItem(rows, cols, item_a)
            self.tableWidget_4.resizeColumnsToContents()  # 设置自适应宽度
            self.hebing(self.tableWidget_4)  # 合并首列同类项

            self.label_83.setStyleSheet("color: green")
            self.label_83.setText('查询成功')

    def pushButton1_30_clicked(self):  # 待分配数据重新分配数据，弹出生产数据填写界面
        pizu = self.comboBox_12.currentText()  # 坯组编号信息获取
        self.Auto_data_generation(pizu)

    def pushButton1_31_clicked(self):  # 开门按钮，根据关门时到现在为止的数据生成生产以及原料数据，进行分配
        global Do_c
        if (not CH_zh):
            self.Auto_data_generation(To_be_allocated_name)
            Do_c = 0
            self.pushButton1_31.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")
            self.pushButton1_14.setStyleSheet("QPushButton {"
                                              "  background-color: white;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        # 生成数据

    def pushButton1_32_clicked(self):  # 放气按钮，放气成功之后才能开门
        global CH_zh
        CH_zh = 0
        self.worker.Gun_p_A.ss_hszhkd = 1
        self.pushButton1_32.setStyleSheet("QPushButton {"
                                          "  background-color: blue;"  # 按钮背景颜色
                                          "  color: white;"  # 文本颜色
                                          "}")

        self.pushButton1_20.setStyleSheet("QPushButton {"
                                          "  background-color: white;"  # 按钮背景颜色
                                          "  color: black;"  # 文本颜色
                                          "}")

    def pushButton1_33_clicked(self):  # A聚焦开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_A.ss_jujiao:
            self.worker.Gun_p_A.ss_jujiao = 0

            self.pushButton1_33.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_A.ss_jujiao = float(self.lineEdit1_21.text())

            self.pushButton1_33.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_39_clicked(self):  # B聚焦开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_B.ss_jujiao:
            self.worker.Gun_p_B.ss_jujiao = 0
            self.pushButton1_39.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_B.ss_jujiao = float(self.lineEdit1_36.text())
            self.pushButton1_39.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_34_clicked(self):  # A偏压开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_A.ss_pianya:
            self.worker.Gun_p_A.ss_pianya = 0
            self.pushButton1_34.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_A.ss_pianya = float(self.lineEdit1_22.text())
            self.pushButton1_34.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_43_clicked(self):  # B偏压开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_B.ss_pianya:
            self.worker.Gun_p_B.ss_pianya = 0
            self.pushButton1_43.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_B.ss_pianya = float(self.lineEdit1_37.text())
            self.pushButton1_43.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_35_clicked(self):  # A灯丝开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_A.ss_dengsi:
            self.worker.Gun_p_A.ss_dengsi = 0
            self.pushButton1_35.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_A.ss_dengsi = float(self.lineEdit1_23.text())
            self.pushButton1_35.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_42_clicked(self):  # B灯丝开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_B.ss_dengsi:
            self.worker.Gun_p_B.ss_dengsi = 0
            self.pushButton1_42.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_B.ss_dengsi = float(self.lineEdit1_39.text())
            self.pushButton1_42.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_36_clicked(self):  # A高压开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_A.ss_gaoya:
            self.worker.Gun_p_A.ss_gaoya = 0
            self.pushButton1_36.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_A.ss_gaoya = float(self.lineEdit1_24.text())
            self.pushButton1_36.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_41_clicked(self):  # B高压开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_B.ss_gaoya:
            self.worker.Gun_p_B.ss_gaoya = 0
            self.pushButton1_41.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_B.ss_gaoya = float(self.lineEdit1_38.text())
            self.pushButton1_41.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_37_clicked(self):  # A束流开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_A.ss_shuliu:
            self.worker.Gun_p_A.ss_shuliu = 0
            self.pushButton1_37.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_A.ss_shuliu = float(self.lineEdit1_25.text())
            self.pushButton1_37.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_40_clicked(self):  # B束流开启按钮，点一次开启，再点一次关闭
        if self.worker.Gun_p_B.ss_shuliu:
            self.worker.Gun_p_B.ss_shuliu = 0
            self.pushButton1_40.setStyleSheet("QPushButton {"
                                              "  background-color: lightgray;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")
        else:
            self.worker.Gun_p_B.ss_shuliu = float(self.lineEdit1_35.text())
            self.pushButton1_40.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

    def pushButton1_38_clicked(self):  # A枪移动开启按钮，点一次开启执行一轮移动，依次按输入信息增加
        global cycle_1
        self.worker.Gun_p_A.mb_X_l = self.worker.Gun_p_A.X_l + int(self.lineEdit1_26.text())
        self.worker.Gun_p_A.mb_Y_l = self.worker.Gun_p_A.Y_l + int(self.lineEdit1_27.text())
        self.worker.Gun_p_A.mb_Z_l = self.worker.Gun_p_A.Z_l + int(self.lineEdit1_30.text())
        self.label_91.setStyleSheet("color: blue")
        self.label_91.setText('正在移动')
        self.worker.time_start_A.emit(self.lineEdit1_31.text(), self.lineEdit1_32.text(),
                                      self.lineEdit1_33.text(), self.lineEdit1_34.text(),
                                      self.lineEdit1_28.text(), self.lineEdit1_29.text(), 0)

    def pushButton1_45_clicked(self):  # B枪移动开启按钮，点一次开启执行一轮移动，依次按输入信息增加
        global cycle_1
        self.worker.Gun_p_B.mb_X_l = self.worker.Gun_p_B.X_l + int(self.lineEdit1_49.text())
        self.worker.Gun_p_B.mb_Y_l = self.worker.Gun_p_B.Y_l + int(self.lineEdit1_50.text())
        self.worker.Gun_p_B.mb_Z_l = self.worker.Gun_p_B.Z_l + int(self.lineEdit1_53.text())
        self.label_130.setStyleSheet("color: blue")
        self.label_130.setText('正在移动')
        self.worker.time_start_B.emit(self.lineEdit1_45.text(), self.lineEdit1_46.text(),
                                      self.lineEdit1_47.text(),
                                      self.lineEdit1_48.text(), self.lineEdit1_51.text(), self.lineEdit1_52.text(), 0)

    def pushButton1_48_clicked(self):  # A枪Z移动开启按钮
        self.worker.Gun_p_A.Z_l = self.worker.Gun_p_A.Z_l + int(self.lineEdit1_30.text())
        self.label_70.setText(str(self.worker.Gun_p_A.Z_l))

    def pushButton1_50_clicked(self):  # A枪X移动开启按钮
        self.worker.Gun_p_A.X_l = self.worker.Gun_p_A.X_l + int(self.lineEdit1_61.text())
        self.label_59.setText(str(self.worker.Gun_p_A.X_l))

    def pushButton1_51_clicked(self):  # A枪Y移动开启按钮
        self.worker.Gun_p_A.Y_l = self.worker.Gun_p_A.Y_l + int(self.lineEdit1_63.text())
        self.label_62.setText(str(self.worker.Gun_p_A.Y_l))

    def pushButton1_56_clicked(self):  # A枪R旋转开启按钮
        self.worker.Gun_p_A.R_l = self.worker.Gun_p_A.R_l + float(self.lineEdit1_65.text())
        self.label_64.setText(str(self.worker.Gun_p_A.R_l))

    def pushButton1_57_clicked(self):  # A枪转台旋转开启按钮
        self.worker.Gun_p_A.ZhTai_l = self.worker.Gun_p_A.ZhTai_l + float(self.lineEdit1_67.text())
        self.label_67.setText(str(self.worker.Gun_p_A.ZhTai_l))

    def pushButton1_49_clicked(self):  # B枪Z移动开启按钮
        self.worker.Gun_p_B.Z_l = self.worker.Gun_p_B.Z_l + int(self.lineEdit1_53.text())
        self.label_110.setText(str(self.worker.Gun_p_B.Z_l))

    def pushButton1_52_clicked(self):  # B枪X移动开启按钮
        self.worker.Gun_p_B.X_l = self.worker.Gun_p_B.X_l + int(self.lineEdit1_60.text())
        self.label_121.setText(str(self.worker.Gun_p_B.X_l))

    def pushButton1_53_clicked(self):  # B枪Y移动开启按钮
        self.worker.Gun_p_B.Y_l = self.worker.Gun_p_B.Y_l + int(self.lineEdit1_62.text())
        self.label_120.setText(str(self.worker.Gun_p_B.Y_l))

    def pushButton1_54_clicked(self):  # B枪R旋转开启按钮
        self.worker.Gun_p_B.R_l = self.worker.Gun_p_B.R_l + float(self.lineEdit1_64.text())
        self.label_118.setText(str(self.worker.Gun_p_B.R_l))

    def pushButton1_55_clicked(self):  # B枪转台旋转开启按钮
        self.worker.Gun_p_B.ZhTai_l = self.worker.Gun_p_B.ZhTai_l + float(self.lineEdit1_66.text())
        self.label_114.setText(str(self.worker.Gun_p_B.ZhTai_l))

    def on_button_click(self, p, b, button):  # 点击生产表中的详情按钮
        # 如果有之前被点击的按钮，将其颜色恢复原样
        if self.current_button and self.current_button != button:
            self.current_button.setStyleSheet("background-color: lightblue; color: black;")
        # 改变当前按钮的颜色
        button.setStyleSheet("background-color: red; color: white;")
        # 更新当前按钮为当前点击的按钮
        self.current_button = button

        self.label_80.setStyleSheet("color: blue")
        self.label_80.setText('获取中，请稍候')
        self.tableWidget.clear()
        if p[0] == "A":
            query1 = """
                    SELECT p.坯组编号, p.边号, p.日期时间, p.[聚焦显示(V)], p.[偏压显示(V)], p.[灯丝显示(A)], p.[高压显示(KV)], p.[束流显示(MA)],
                           p.扫描频率, p.扫描X轴, p.扫描Y轴, p.偏转X轴, p.偏转Y轴, p.合轴X轴, p.合轴Y轴, p.像散X轴, p.像散Y轴, p.枪室真空度, p.焊室真空度, 
                           p.R角度, p.转台角度, p.X坐标, p.Y坐标, p.Z坐标
                    FROM persons_A p
                    WHERE p.坯组编号=%s AND p.边号=%s
                    """
        elif p[0] == "B":
            query1 = """
                    SELECT p1.坯组编号, p1.边号, p1.日期时间, p1.[聚焦显示(V)], p1.[偏压显示(V)], p1.[灯丝显示(A)], p1.[高压显示(KV)], p1.[束流显示(MA)],
                           p1.扫描频率, p1.扫描X轴, p1.扫描Y轴, p1.偏转X轴, p1.偏转Y轴, p1.合轴X轴, p1.合轴Y轴, p1.像散X轴, p1.像散Y轴, p1.枪室真空度, p1.焊室真空度, 
                           p1.R角度, p1.转台角度, p1.X坐标, p1.Y坐标, p1.Z坐标
                    FROM persons_B p1
                    WHERE p1.坯组编号=%s AND p1.边号=%s
                    """
        liemin1 = ["坯组编号", "边号", "日期时间", "聚焦(V)", "偏压(V)", "灯丝(A)", "高压(KV)", "束流(MA)",
                   "扫描频率", "扫描X轴", "扫描Y轴", "偏转X轴", "偏转Y轴", "合轴X轴", "合轴Y轴", "像散X轴", "像散Y轴",
                   "枪室真空度", "焊室真空度", "R角度", "转台角度"]
        try:
            self.cursor.execute(query1, (p, b))
            results1 = self.cursor.fetchall()  # 获取查询到的所有信息
            self.conn.commit()
            print(results1)
            if results1 == []:
                self.label_80.setStyleSheet("color: red")
                self.label_80.setText('查询为空，请更换条件')
            else:

                # 遍历二维数组，将第三列的 datetime 转换为字符串
                # 确保 results1 是可以修改的  改为results2数组存储数据
                results2 = [list(row) for row in results1]  # 将每个元组转换为列表
                results3 = [list(row) for row in results1]
                # print(results2)
                for row2 in results3:
                    # 将第三列的 datetime 转换为字符串
                    # print(row2)
                    row2[2] = row2[2].strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                for row1 in results2:
                    #转换为 Qdatetime
                    row1[2] = QDateTime(row1[2].date(), row1[2].time())  # 转为Qdatetime

                global results0_1  #存储最终转化的字典信息
                results0_1.clear()
                global results1_1
                #生成字典数据：坯组编号作为第一层字典键，边号作为第二层字典键，对数据进行存储，之后发送至图像显示
                # 使用 defaultdict 动态生成字典
                results0_1 = defaultdict(list)
                for row in results2:
                    key = row[0]  # 第一列作为键
                    values = row[1:]  # 其余列作为值
                    results0_1[key].append(values)  # 将值添加到对应键的列表中

                # 将 defaultdict 转换为普通字典
                results0_1 = dict(results0_1)
                # print(result)
                for key, values in results0_1.copy().items():
                    # 动态生成字典
                    results = defaultdict(list)
                    for row in values:
                        key1 = row[0]  # 第一列作为键
                        values1 = row[1:]  # 其余列作为值
                        results[key1].append(values1)  # 将值添加到对应键的列表中
                    results = dict(results)
                    results0_1[key] = results

                self.tableWidget.setRowCount(len(results3))  # 设置行数
                self.tableWidget.setColumnCount(21)  # 设置列数
                self.tableWidget.setHorizontalHeaderLabels(liemin1)  # 设置列名称

                for rows, resultrow in enumerate(results3):  # 对数据集合中的每行进行操作
                    for cols, resultcol in enumerate(resultrow):
                        item_a = QTableWidgetItem(str(resultcol))
                        item_a.setTextAlignment(Qt.AlignCenter)  # 设置内容居中
                        self.tableWidget.setItem(rows, cols, item_a)
                self.tableWidget.resizeColumnsToContents()  # 设置自适应宽度
                self.hebing(self.tableWidget)  # 合并首列同类项
                self.label_80.setStyleSheet("color: green")
                self.label_80.setText('查询成功')
        except:
            self.label_80.setStyleSheet("color: red")
            self.label_80.setText('查询超限，请更换条件')

    def pushButton_2_clicked(self):  #3D图像缩放按钮，弹出对应窗口
        print(self._container.size().width())
        if self._container.size().width() > 400:
            self._container.setFixedSize(250, 400)
        else:
            self._container.setFixedSize(600, 400)

    #临时测试按钮
    def pushButton1_14_clicked(self):  #关门按钮
        global Do_c
        global To_be_allocated_name
        time = QDateTime.currentDateTime()
        To_be_allocated_name = time.toString('yyMM')  # 将当前时间转换成字符串类型
        Do_c = 1
        self.pushButton1_14.setStyleSheet("QPushButton {"
                                          "  background-color: blue;"  # 按钮背景颜色
                                          "  color: white;"  # 文本颜色
                                          "}")
        self.pushButton1_31.setStyleSheet("QPushButton {"
                                          "  background-color: white;"  # 按钮背景颜色
                                          "  color: black;"  # 文本颜色
                                          "}")

    def pushButton1_20_clicked(self):  #抽真空按钮
        global CH_zh
        if (Do_c):
            CH_zh = 1
            self.worker.Gun_p_A.ss_hszhkd = 0.00001
            self.pushButton1_20.setStyleSheet("QPushButton {"
                                              "  background-color: blue;"  # 按钮背景颜色
                                              "  color: white;"  # 文本颜色
                                              "}")

            self.pushButton1_32.setStyleSheet("QPushButton {"
                                              "  background-color: white;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")

    def pushButton1_16_clicked(self):  # A下束焊接按钮
        global HAN_j_A
        global cycle_1
        HAN_j_A = not HAN_j_A
        if not CH_zh and HAN_j_A:
            HAN_j_A = 0
        if HAN_j_A:
            try:
                self.worker.time_start1_A.emit(cycle_1)  # 定时器运行开始并时间设定
                self.pushButton1_16.setStyleSheet("QPushButton {"
                                                  "  background-color: blue;"  # 按钮背景颜色
                                                  "  color: white;"  # 文本颜色
                                                  "}")
            except:
                self.worker.time_stop1_A.emit()  # 停止多线程中的定时器
                self.pushButton1_16.setStyleSheet("QPushButton {"
                                                  "  background-color: red;"  # 按钮背景颜色
                                                  "  color: white;"  # 文本颜色
                                                  "}")
        else:
            self.worker.time_stop1_A.emit()  # 停止多线程中的定时器
            self.pushButton1_16.setStyleSheet("QPushButton {"
                                              "  background-color: white;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")

    def pushButton1_44_clicked(self):  # B下束焊接按钮
        global HAN_j_B
        global cycle_1
        HAN_j_B = not HAN_j_B
        if not CH_zh and HAN_j_B:
            HAN_j_B = 0
        if HAN_j_B:
            try:
                self.worker.time_start1_B.emit(cycle_1)  # 定时器运行开始并时间设定
                self.pushButton1_44.setStyleSheet("QPushButton {"
                                                  "  background-color: blue;"  # 按钮背景颜色
                                                  "  color: white;"  # 文本颜色
                                                  "}")
            except:
                self.worker.time_stop1_B.emit()
                self.pushButton1_44.setStyleSheet("QPushButton {"
                                                  "  background-color: red;"  # 按钮背景颜色
                                                  "  color: white;"  # 文本颜色
                                                  "}")
        else:
            self.worker.time_stop1_B.emit()
            self.pushButton1_44.setStyleSheet("QPushButton {"
                                              "  background-color: white;"  # 按钮背景颜色
                                              "  color: black;"  # 文本颜色
                                              "}")

    def pushButton_clicked(self):  # 一键复位按钮，按下事件
        # 获取布局中的对象，使其位置与缩放复位
        item0 = self.verticalLayout_2.itemAt(0)
        item1 = self.verticalLayout_2.itemAt(1)

        # 检查 item 是否为 None
        if item0 is None and item1 is None:
            print("No item found in the layout.")
            return
        widget0 = item0.widget()
        widget1 = item1.widget()
        if widget0 is None and widget1 is None:
            print("The item does not contain a widget.")
            return
        if isinstance(widget0, QChartView):  # 判断是否为QChartView
            print(1)
            chart0 = widget0.chart()
            chart0.zoomReset()  # 归位
        if isinstance(widget1, QChartView):  # 判断是否为QChartView
            print(2)
            chart1 = widget1.chart()
            chart1.zoomReset()  # 归位

    # -----------------一键归位------------------

    # -----------------下拉框函数绑定----------------
    def comboBox_10_change(self):  #新建表下拉框选择初始文本发生变化时动作
        global newList_Template
        sqls = self.load_sqls()
        for sql in sqls:
            if sql["Variable"] == self.comboBox_10.currentText():
                newList_Template = sql["data"]
        self.textEdit1.setText(newList_Template)  # 数据库新建表内容输入框

    # --------------------------------------------

class ui_denglu(Ui_Dialog, QDialog):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.USER_DATA_FILE = 'H_S_JSON/users.json'
        #-------------权限初始化-----------
        if permissions_main == "admin":
            self.set_admin()
        elif permissions_main == "user":
            self.set_user()
        else:
            self.set_norole()
        #---------------显示信息初始化------------
        self.lineEdit_5.setText(username_main)  # 在修改密码框上显示账号信息
        self.label_17.setText(username_main)  # 在登录页面上显示登录名信息
        self.label_18.setText(permissions_main)  # 在登录页面上显示权限信息
        #----------------下拉框内容填充----------------
        for i in self.load_users():
            self.comboBox.addItem(i['username'])
        self.comboBox_2.addItem("admin")
        self.comboBox_2.addItem("user")
        #------------------按钮绑定-------------------
        self.tabWidget.tabBarClicked.connect(self.tab_4_clicked)  # tab_4修改与删除页面切换标签被点击
        self.pushButton.clicked.connect(self.pushButton_clicked)  # 登录按钮被按下时的方法绑定
        self.pushButton_4.clicked.connect(self.pushButton_4_clicked)  # 修改按钮被按下时的方法绑定
        self.pushButton_3.clicked.connect(self.pushButton_3_clicked)  # 新建按钮被按下时的方法绑定
        self.pushButton_5.clicked.connect(self.pushButton_5_clicked)  # 退出登录按钮被按下时的方法绑定
        self.pushButton_2.clicked.connect(self.pushButton_2_clicked)  # 取消按钮被按下时的方法绑定
        self.pushButton_7.clicked.connect(self.pushButton_7_clicked)  # 修改账号权限方法绑定
        self.pushButton_6.clicked.connect(self.pushButton_6_clicked)  # 删除账号方法绑定

    def set_admin(self):  #管理者权限设置
        self.tab_2.setEnabled(True)  #修改密码
        self.tab_3.setEnabled(True)  #新增
        self.tab_4.setEnabled(True)  #修改与删除

    def set_user(self):  #操作者角色权限设置
        self.tab_2.setEnabled(True)  # 修改密码
        self.tab_3.setEnabled(False)  #新增
        self.tab_4.setEnabled(False)  #修改与删除

    def set_norole(self):  #没有角色时的权限设置
        self.tab_2.setEnabled(False)  # 修改密码
        self.tab_3.setEnabled(False)  #新增
        self.tab_4.setEnabled(False)  #修改与删除

    def load_users(self):  #读取账号文件信息
        with open(self.USER_DATA_FILE, 'r') as file:
            data = json.load(file)
        return data['users']

    def save_users(self, users):  #存储用户
        with open(self.USER_DATA_FILE, 'w') as file:
            json.dump({"users": users}, file, indent=4)

    def authenticate_user(self, username, password):  #用户登录
        users = self.load_users()
        hashed_password = sha256(password.encode()).hexdigest()
        print(hashed_password)
        print(users)
        for user in users:
            if user['username'] == username and user['password'] == hashed_password:
                return True, "成功登录", user['username'], user['permissions']
        return False, "密码错误", None, None

    def get_user_permissions(self, username):  #获取用户权限
        users = self.load_users()
        for user in users:
            if user['username'] == username:
                return user['permissions']
        return []

    def add_user(self, username, password, permissions):  #添加新用户
        try:
            users = self.load_users()
            hashed_password = sha256(password.encode()).hexdigest()
            users.append({
                "username": username,
                "password": hashed_password,
                "permissions": permissions
            })
            self.save_users(users)
            return True
        except:
            return False

    def pushButton_clicked(self):  #登录按钮绑定方法
        usernamed = self.comboBox.currentText()
        passwordd = self.lineEdit_2.text()
        global username_main
        global permissions_main
        success, message, username_main, permissions_main = self.authenticate_user(usernamed, passwordd)
        if success:
            self.label_4.setStyleSheet("color: green")
            self.label_4.setText(message)
            self.lineEdit_5.setText(username_main)  #在修改密码框上显示账号信息
            self.label_17.setText(username_main)  #在登录页面上显示登录名信息
            self.label_18.setText(permissions_main)  #在登录页面上显示权限信息
            if permissions_main == "admin":
                self.set_admin()
            elif permissions_main == "user":
                self.set_user()
            else:
                self.set_norole()
            # 这里可以切换到主界面
        else:
            self.label_4.setStyleSheet("color: red")
            self.label_4.setText(message)

    def pushButton_4_clicked(self):  #修改按钮绑定方法
        try:
            username = username_main
            password = self.lineEdit_4.text()
            users = self.load_users()
            hashed_password = sha256(password.encode()).hexdigest()
            for user in users:
                if user['username'] == username:
                    user['password'] = hashed_password
            self.save_users(users)
            self.label_12.setStyleSheet("color: green")
            self.label_12.setText("修改成功")
            self.lineEdit_4.clear()
        except:
            self.label_12.setStyleSheet("color: red")
            self.label_12.setText("修改失败")

    def pushButton_3_clicked(self):  #新建按钮绑定方法
        user1 = self.lineEdit.text()
        password1 = self.lineEdit_3.text()
        permissions1 = self.comboBox_2.currentText()
        mag = self.add_user(user1, password1, permissions1)  #新建账号密码并绑定权限
        if mag:
            for i in self.load_users():
                self.comboBox.addItem(i['username'])
            self.label_6.setStyleSheet("color: green")
            self.label_6.setText("新建成功")
        else:
            self.label_6.setStyleSheet("color: red")
            self.label_6.setText("新建失败")

    # tab_4修改与删除页面切换标签被点击
    def tab_4_clicked(self, index):
        self.label_25.setStyleSheet("color: black")
        self.label_25.setText("状态")
        self.label_4.setStyleSheet("color: black")
        self.label_4.setText("状态")
        self.label_12.setStyleSheet("color: black")
        self.label_12.setText("状态")
        self.label_6.setStyleSheet("color: black")
        self.label_6.setText("状态")
        self.label_25.setStyleSheet("color: black")
        self.label_25.setText("状态")
        self.label_26.setStyleSheet("color: black")
        self.label_26.setText("状态")
        if index == 0:
            self.comboBox.clear()
            for i in self.load_users():
                self.comboBox.addItem(i['username'])
        if index == 3:
            self.comboBox_5.clear()
            self.comboBox_4.clear()
            self.comboBox_3.clear()
            self.comboBox_5.addItem("admin")
            self.comboBox_5.addItem("user")
            for i in self.load_users():
                self.comboBox_3.addItem(i['username'])
                self.comboBox_4.addItem(i['username'])

    def pushButton_7_clicked(self):  #修改密码与权限按钮
        try:
            username1 = self.comboBox_4.currentText()
            password1 = self.lineEdit_6.text()
            permissions1 = self.comboBox_5.currentText()
            users = self.load_users()

            if password1 != None:
                hashed_password = sha256(password1.encode()).hexdigest()
                for user in users:
                    if user['username'] == username1:
                        user['password'] = hashed_password
                        user['permissions'] = permissions1
                        break
            else:
                for user in users:
                    if user['username'] == username1:
                        user['permissions'] = permissions1
                        break

            self.save_users(users)
            self.label_25.setStyleSheet("color: green")
            self.label_25.setText("修改成功")
            self.lineEdit_4.clear()
        except:
            self.label_25.setStyleSheet("color: red")
            self.label_25.setText("修改失败")

    def pushButton_6_clicked(self):  # 删除账号按钮
        try:
            username1 = self.comboBox_3.currentText()
            users = self.load_users()

            for user in users:
                if user['username'] == username1:
                    users.remove(user)
                    break
            self.save_users(users)
            self.label_26.setStyleSheet("color: green")
            self.label_26.setText("删除成功")
        except:
            self.label_26.setStyleSheet("color: red")
            self.label_26.setText("删除失败")

    def pushButton_5_clicked(self):  #退出登录按钮绑定方法
        global window1
        window1.close()

    def pushButton_2_clicked(self):  #取消按钮绑定方法
        global window1
        window1.close()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    app = QApplication.instance()
    app.aboutToQuit.connect(lambda: print("\n应用程序即将退出"))
    # QApplication.setAttribute(Qt.AA_UseOpenGLES)
    window = ui_main()

    window.show()
    print("main run")
    sys.exit(app.exec())
